简体   繁体   中英

Why does the following line of code cause my program to seg fault?

In the following code:

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

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

    char input[20];
    fgets(input, sizeof(input), stdin);
    char * pch;
    pch = strtok(input, " ");
    int i = 0;
    int nums[3];
    while (pch != NULL)
    {
        printf ("%s\n",pch);
        pch = strtok(NULL, " ");
        //nums[i] = atoi(pch);
        i++;
    }


    return 0;
}

Input of

1 2 3

Gives:

1
2
3

When I uncomment the commented line I get:

1
2
3

Segmentation fault: 11

Why does this one line cause a seg fault?

The main thing is that you need to run atoi(pch) before calling strtok again:

printf ("%s\n",pch);
nums[i++] = atoi(pch);
pch = strtok(NULL, " ");

Otherwise the last call to atoi passes in the null pointer as an argument and atoi crashes.

Another detail of interest is that input might contain a newline character at the end. This won't be a problem for atoi , but it will cause your loop to iterate 4 times and write after the end of nums . Although most likely it will not cause your program to crash, this is still undefined behavior and you should insert a check for the array boundaries to prevent it.

Debug your code to make it correct and robust.

Tip 1: Avoid invalid memory access in raw arrays

if (i >= 0 && i < 3)
{
   // The value of i is a Valid index for "int nums[3];"
   nums[i] = atoi(pch);
}
else
{
   // The value of i is NOT a Valid index for "int nums[3];", so why even try?
   // Using "nums[i]" here would cause undefined behaviour.
}

Tip 2: Narrow down your problem

int currentInt = atoi(pch);
nums[i] = currentInt;

Which of these lines is crashing?

If it's the second, you should be able to prevent it with the range checking I suggested above.

If it's the first, int currentInt = atoi(pch);, it means that atoi is crashing, because its return value is exactly int so the assignment of its result to currentInt is safe.

Why could atoi crash? Now you've narrowed down your problem. Continue narrowing it down until you find what it is.

remain newline

change

pch = strtok(NULL, " ");

to

pch = strtok(NULL, " \n");

You must check the return of strtok (return NULL if no more token) and check i, because this var must not go up to 3, cause nums array is allocated only for 3 int.

while (pch != NULL && i < 3)
    {
        printf ("%s\n",pch);
        pch = strtok(NULL, " ");
        if (pch != NULL)
          nums[i] = atoi(pch);
        i++;
    }

because you loop outside the array boundary

int i = 0;
int nums[3];
while (pch != NULL)
{
    printf ("%s\n",pch);
    pch = strtok(NULL, " ");  
    nums[i] = atoi(pch);      // i == 3 will cause the issue
    i++;
}

instead try

int i = 0;
int nums[3];
for (pch = strtok(input, " "); pch != NULL && i < 3; pch = strtok(NULL," "))
{
    printf ("%s\n",pch);
    nums[i++] = atoi(pch); 
}

Using strtok you are getting one character each time and putting it in the array.
But, strtok returns the string before the delimiter or end of string.
for the last value, ie 3 , it also having a \\n appended to it, and you are trying to put it in as a single character.

Simply put the value to the array before fetching the next one

int i = 0;
int nums[3];
while (pch != NULL)
{
    printf ("%s\n",pch);
    nums[i] = atoi(pch);
    pch = strtok(NULL, " ");
    i++;
}
/*// Testing the array
for(i = 0; i< 3; i++)
   printf("%d ",nums[i]);
*/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM