简体   繁体   English

为什么以下代码行导致我的程序出现段错误?

[英]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: 最主要的是您需要再次调用strtok 之前运行atoi(pch)

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. 否则,对atoi的最后一次调用会将null指针作为参数传递,并且atoi崩溃。

Another detail of interest is that input might contain a newline character at the end. 另一个有趣的细节是input可能在末尾包含换行符。 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 . 对于atoi不会出现问题,但这会使您的循环迭代4次并在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 提示1:避免在原始阵列中进行无效的内存访问

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 提示2:缩小问题范围

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. 如果是第一个int currentInt = atoi(pch);,则意味着atoi正在崩溃,因为其返回值恰好是int,因此将结果分配给currentInt是安全的。

Why could atoi crash? 为什么atoi会崩溃? 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. 您必须检查strtok的返回值(如果没有更多的令牌,则返回NULL)并检查i,因为此var不得超过3,因为nums数组仅分配给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. 使用strtok您每次都会得到一个字符并将其放入数组中。
But, strtok returns the string before the delimiter or end of string. 但是, strtok在分隔符或字符串结尾之前返回字符串。
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. 对于最后一个值,即3 ,它还附加了一个\\n ,并且您试图将其作为单个字符放入。

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]);
*/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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