Formas de construir cuerdas en c

I'm building a string here based on 4 arguments and calling it with system(), but seems kinda messy the way i have done it. Is there a more correct way i should have done this and not use all those strcat and str1-4?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{

    char str1[40] = "sed -n 's/.*\\(";
    char str2[] = "\\)\\(.*\\)\\(";
    char str3[] = "\\).*/\\2/p' ";
    char str4[] = " > ";

    if (argc != 5)
    {
        fprintf (stderr, "Usage %s <LogFile> <token1> <token2> <DumpFile>\n",
                argv[0]);
                exit(EXIT_FAILURE);
    }

    strcat(str1, argv[2]);
    strcat(str1, str2);
    strcat(str1, argv[3]);
    strcat(str1, str3);
    strcat(str1, argv[1]);
    strcat(str1, str4);
    strcat(str1, argv[4]);

    system(str1);

    return 0;
}

preguntado el 30 de enero de 12 a las 19:01

6 Respuestas

One problem with your code is that you're not checking the arguments fit in the 40 bytes.

Probablemente usaría snprintf:

snprintf(str, LENGTH, "sed -n 's/.*\\(%s...", argv[2]...);

Respondido el 30 de enero de 12 a las 23:01

Which standard are you referring to? It is standard in both the current (C2011) and the previous (C99) versions of the C standard. The only place it isn't standard is Windows where Microsoft is stuck in a timewarp and insists that only C89 is standard and hides the more recent names behind an underscore: _snprintf() Etc.- Jonathan Leffler

@JonathanLeffler For some reason I was under the idea that it's not specified in C99. I see it is. Awesome! - cnicutar

This saves on the quadratic behaviour of repeated strcat(). OTOH, that is lost in the noise if you call system().

char str1[4096];
char str0[] = "sed -n 's/.*\\(";

sprintf(str1, "%s%s%s%s%s%s%s%s", str0, argv[2], str2, argv[3], str3, argv[1], str4, argv[4]);

Podrías usar snprintf() if you're worried about buffer overflows (and you should be; 40 bytes in str1 is not enough; you left the 96 off the end, as in char str1[4096];). You could check the return value to see how many characters got written.

Respondido el 30 de enero de 12 a las 23:01

"You left the 96 off the end" alone merits a +1. :-) - ruakh

Siempre hay sprintf which will make your life simpler. Make sure if you use sptrintf the buffer is large enough for the result. There is also a safer version snprintf which will do the bounds checking for you.

Respondido el 30 de enero de 12 a las 23:01

The only problem is that you may get buffer overflow (if the input is too long). to fix it, check the length of the strings (using strlen), and allocate enough memory to contain the string you want.

After you allocated enough memory, you can use a loop, or let sprintf haga el trabajo por usted.

Respondido el 30 de enero de 12 a las 23:01

str1 is only 40 bytes long, and you're appending too much data to it. An stack overflow is likely to occur. I would do:

char buffer[1000]; // Choose a reasonable size
snprintf(buffer, sizeof(buffer),
    "sed -n 's/.*\\(%s\\)\\(.*\\)\\(%s\\).*/\\2/p' %s > %s",
    argv[2], argv[3], argv[1], argv[4]);

Respondido el 30 de enero de 12 a las 23:01

If you want your code to handle arbitrarily long arguments then you will need to allocate the character buffer dynamically with malloc.

  1. Create a local variable to calculate the total length required and use repeated calls to strlen to calculate that length.
  2. Llame al malloc remembering to add one more character for the null-terminator.
  3. Utilizan strcpy or strcat multiple times to build up the string.
  4. Llame al system.
  5. Llame al free (or don't bother if your process is about to terminate).

Respondido el 30 de enero de 12 a las 23:01

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.