views:

97

answers:

7

The following piece of code gives a segmentation fault when allocating memory for the last arg. What am I doing wrong? Thanks.

    int n_args = 0, i = 0;
    while (line[i] != '\0')
    {
        if (isspace(line[i++]))
            n_args++;
    }

    for (i = 0; i < n_args; i++)
        command = malloc (n_args * sizeof(char*));

    char* arg = NULL;
    arg = strtok(line, " \n");
    while (arg != NULL)
    {
        arg = strtok(NULL, " \n");
            command[i] = malloc ( (strlen(arg)+1) * sizeof(char) );
        strcpy(command[i], arg);
        i++;
    }

Thanks.

+4  A: 

You don't reset the value of i after the for loop, so i is equal to n_args when you reach the bottom block. Trying to access command[i] at that point accesses uninitialized memory and segfaults.

The real lesson here is not to reuse variables in this manner without a good reason. Your code will be more robust and easier to read if you use something other than i in the middle for loop.

JSBangs
Good reading, that.
dmckee
A: 

For a line comprising two arguments separated by a single space, n_args will be 1 rather than 2. This is probably not what you want.

Steve Emmerson
+2  A: 
for (i = 0; i < n_args; i++)
        command = malloc (n_args * sizeof(char*));

should become just

command = malloc (n_args * sizeof(char*))

because you just want to alloc an array of n_args elements, and

while (arg != NULL)
    {
        arg = strtok(NULL, " \n");
        command[i] = malloc ( (strlen(arg)+1) * sizeof(char) );
        strcpy(command[i], arg);
        i++;
    }

should become:

arg = strtok(NULL, " \n");
while (arg != NULL) {
    command[i] = malloc ( (strlen(arg)+1) * sizeof(char) );
    strcpy(command[i], arg);
    i++;
    arg = strtok(NULL, " \n");
}

to avoid strlen on a null pointer.

Julien Lebosquain
Putting `strtok(NULL` at the end avoid also skipping the first parameter.
tristopia
Additionally i should be reset to 0 before the loop: while (arg != NULL)...
Maciej Hehl
A: 

I think you have a few funny things going on here (if I'm reading this correctly).

This block:

for (i = 0; i < n_args; i++)
    command = malloc (n_args * sizeof(char*));

Should be this:

    command = malloc (n_args * sizeof(char*));

No need to reallocate command over and over again.

As for the seg fault though, could be because you are re-using the i variable without resetting it to zero again first.

Eric Petroelje
A: 

You're throwing away your first arg? Is that intentional? In case it isn't

int n_args = 1;     /* We need one element more than spaces */
int i = 0;
while (line[i])
{
    if (isspace(line[i++]))
        n_args++;
}

command = malloc (n_args * sizeof(char*));

char* arg = NULL;
arg = strtok(line, " \n");
i = 0;        /***** You forgot to reset that value, that was your segfault !!! */
while (arg)
{
    command[i++] = strdup(arg);  /* It does your malloc/strlen/strcpy */
    arg = strtok(NULL, " \n");
}

You forgot to reset your i index, which reaches outside your allocated array in your code.

tristopia
I add it as comment, don't want to reedit my answer. Minor quibble, it's bad style to reuse the variable for different purposes, you reuse i in 3 different places, in 2 of them it indexes the same thing so it's OK in my eyes. The first use is different, index on `line` which is semantically different, I would use another variable instead. It won't do any difference for the compiler, but it will be easier to read if variable do not change role in the middle.
tristopia
A: 

Try arranging this loop properly:

 while (arg != NULL)
    {
        arg = strtok(NULL, " \n");
            command[i] = malloc ( (strlen(arg)+1) * sizeof(char) );
        strcpy(command[i], arg);
        i++;
    }

the line "arg=strtok..." does 2 things wrongs:

  1. Skips the first argument.
  2. Doesn't check the return code, so if arg==NULL then strlen(arg) will SEGFAULT.

Do this instead:

 while (arg != NULL)
    {
        command[i] = malloc ( (strlen(arg)+1) * sizeof(char) );
        strcpy(command[i], arg);
        i++;
        arg = strtok(NULL, " \n");
    }
Sridhar Iyer
A: 

It is hard to figure out what you are trying to do.

It looks like you are looking at the number of spaces in the command line to see how many command line arguments you have. Are all of your command line args a single character? The malloc is only reserving enough space for one character per arg.

If your args are just one char each:

command = malloc(strlen(line));
i = 0;
j = 0;
while(line[j]) {
   if(!isspace(line[j])){
      command[i++] = line[j];
   }
   j++;
}
Jim Tshr