strncpy()分段错误:可疑的strtok()操作?

strncpy()分段错误:可疑的strtok()操作?,c,string,segmentation-fault,C,String,Segmentation Fault,我正在写一个程序,从用户那里提取行并解析它们,作为家庭作业。 我受限于一定的内存量,因此我只能使用下面使用的变量 我的代码有一个分段错误,使用gdb发现它源于下面的strncpy()函数调用。我能看到发生这种情况的唯一原因是str有问题,这是由我使用strtok()引起的。如果有人能指出我是如何错误地使用strtok()的,或者是一种不添加任何变量而通过空格解析字符串的替代方法,我将非常感激 字符串的格式为“00 COMMAND 0”,我试图将最后一位放入数组,同时保留该命令以供以后计算。命令的

我正在写一个程序,从用户那里提取行并解析它们,作为家庭作业。 我受限于一定的内存量,因此我只能使用下面使用的变量

我的代码有一个分段错误,使用gdb发现它源于下面的strncpy()函数调用。我能看到发生这种情况的唯一原因是str有问题,这是由我使用strtok()引起的。如果有人能指出我是如何错误地使用strtok()的,或者是一种不添加任何变量而通过空格解析字符串的替代方法,我将非常感激

字符串的格式为“00 COMMAND 0”,我试图将最后一位放入数组,同时保留该命令以供以后计算。命令的长度从3到4个字符不等

char str[11];
*count = 0;


while( scanf( "%[^\n]%*c", str ) == 1 )
{
    printf( "\n%s\n", str );
    strtok( str, " " );
    strtok( NULL, " " );
    memory[*count] = atoi( strtok( NULL, " " ) );


    strtok( str, " " );
    strncpy( str, strtok( NULL, " " ), sizeof( str ) );

strtok通过在标记末尾添加“\0”字符来更改str。因此,第二次使用str作为参数调用strtok时,它只会看到字符串的“00”部分。 最简单的修复方法是通过标记化第一次保存命令部分:

strtok( str, " " );
strncpy( str, strtok( NULL, " " ), sizeof( str ) );
memory[*count] = atoi( strtok( NULL, " " ) );
当然,您还应该检查strtok的返回值,以确保没有传递错误的输入

编辑-oops。我没有意识到您想要将命令存储回str。将命令部分复制回str应该是安全的,因为它必须比第一个参数+命令短。不过,这看起来确实有点可疑。最好为命令使用另一个指针变量。它只有另外4-8个字节(取决于您的系统)


在我看来,要做的第一件事是从
strtok()
捕获并打印返回值,或者在您期望非null返回时检查它们是否为null

鉴于守则的第二部分:

strtok(str, " ");
strncpy(str, strtok(NULL, " "), sizeof(str));
您正在使用
strncpy()
在字符串本身上复制一段
str
。这是未定义的行为:

如果复制发生在重叠的对象之间,则行为未定义


当您调用未定义的行为时,任何事情都可能发生。

只需将第二个令牌指针保存到'str'。不需要复制

printf( "\n%s\n", str );
strtok( str, " " ); /* apparently you don't care about this token */
str = strtok( NULL, " " );  /* 'str' now points to COMMAND */
memory[*count] = atoi( strtok( NULL, " " ) );

不管您在做什么,
atoi(strtok
总是有风险的,因为
strtok
可能返回NULL。在传递到
atoi
(或
strncpy
)之前检查返回值。还要注意,如果源字符串足够长,则
strncpy
不会为null并终止其缓冲区;因此,如果您以后想将
str
作为字符串访问,则明智的做法是将
'\0'
放在末尾,或者更好的做法是,完全避免
strncpy
。我知道,我会完全避免strncpy当然有问题,但是我需要使用的编译器设置不支持其他选项。谢谢你的回答。谢谢你的回答,但是除非我弄错了,否则我们不能这样分配数组,这就是为什么我一开始就在与strncpy打交道。
printf( "\n%s\n", str );
strtok( str, " " ); /* apparently you don't care about this token */
str = strtok( NULL, " " );  /* 'str' now points to COMMAND */
memory[*count] = atoi( strtok( NULL, " " ) );