来自`strsep`的字符串标记不打印(seg fault)

时间:2018-03-20 21:23:41

标签: c string pointers strsep

我正在使用较小的代码来测试较大(初学者)程序的功能,但是我在显示已从字符串中拉出的令牌时遇到问题。

我找到并使用了:

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

int main()
{

char *string, *found;

string = strdup ("1/2/3");
printf("Original string: '%s'\n",string);

while ((found = strsep(&string,"/")) != NULL )
  printf ("%s\n",found);

return (0);
}

这样可以正常工作,一次打印一个标记作为字符串。

然后当我尝试移动到用户输入的字符串时:

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

int main()
{
  char string[13];
  char *found, *cp = string;

  fprintf(stderr, "\nEnter string: ");
  scanf("%12s",string);
  printf("Original string: '%s'\n",string);

  while((found =  strsep(&cp,"/,-")) != NULL )
    printf("Test 1"); /*To pinpoint where the seg fault arises*/
    printf("%s\n",found);

  return(0);
}

我在printf("%s\n",found);行上遇到了段错误。我正在掌握指针,数组和字符串的基础知识,但显然我错过了一些东西,并希望有人告诉我它是什么!

另外 - 如果我更改printf("%s\n",found);的参数,例如到printf("%i\n",found);我得到一些随机性,但总是正确的金额,例如如果我输入1/2/3我得到三行垃圾,输入1111/2222会得到两行。我尝试了%c,%i,%d,%p,它们都做了同样的事情,但%s seg故障。

我完全被难倒了。

2 个答案:

答案 0 :(得分:3)

段错是因为你错过了while周围的大括号。您将继续打印“测试1”,直到strsep返回NULL,然后您尝试打印该结果(和段错误)。

有几个警告标志(可能是-Wall),gcc会在这里帮忙:

sep.c:13:3: warning: this ‘while’ clause does not guard... [-Wmisleading-indentation]
   while((found =  strsep(&cp,"/,-")) != NULL )
   ^~~~~
sep.c:15:5: note: ...this statement, but the latter is misleadingly indented as if it is guarded by the ‘while’
     printf("%s\n",found);
     ^~~~~~

while周围添加大括号,程序按预期工作:

./sep 

Enter string: abc/def
Original string: 'abc/def'
Test 1abc
Test 1def

答案 1 :(得分:2)

这是问题所在:

while((found =  strsep(&cp,"/,-")) != NULL )
    printf("Test 1"); /*To pinpoint where the seg fault arises*/
    printf("%s\n",found);

并且你认为你在循环中正在做printf两个,但实际上这个 代码相当于

while((found =  strsep(&cp,"/,-")) != NULL )
{
    printf("Test 1"); /*To pinpoint where the seg fault arises*/
}
    printf("%s\n",found);

这意味着printf("%s\n",found);基本上正在printf("%s\n",NULL); 这是未定义的行为,可能会导致段错误。

请注意,在C缩进中对编译器无关紧要。所以你需要 在代码周围使用{}

while((found =  strsep(&cp,"/,-")) != NULL )
{
    printf("Test 1"); /*To pinpoint where the seg fault arises*/
    printf("%s\n",found);
}

这样做我得到了

$ ./a 

Enter string: aa/bb/cc/dd
Original string: 'aa/bb/cc/dd'
Test 1aa
Test 1bb
Test 1cc
Test 1dd

还要注意你的第一个代码是泄漏内存,你没有释放 已分配strdup返回的内存。你必须保存指向它的指针:

#include <stdio.h>
#include <stdlib.h> // for the free function
#include <string.h>

int main()
{

    char *orig = *string, *found;

    orig = string = strdup ("1/2/3");
    printf("Original string: '%s'\n",string);

    while ((found = strsep(&string,"/")) != NULL )
      printf ("%s\n",found);

    free(orig);

    return 0;
}

修改

Stephen Newell和我似乎都没有同样的问题 更正后的代码版本。 OP提供了onlinegdb.com的链接 显示更正的版本以段错结束。

我在ideone.com上尝试了相同的代码,我也得到了段错误。那似乎 对我来说很奇怪,所以我打开了strsep的手册页,发现了这个:

  

man strsep

     

<强>概要

   #include <string.h>

   char *strsep(char **stringp, const char *delim);
     

glibc的功能测试宏要求(参见feature_test_macros(7)):

     

strsep()

Since glibc 2.19:
    _DEFAULT_SOURCE
Glibc 2.19 and earlier:
    _BSD_SOURCE

这里重要的部分是:因为glibc 2.19:_DEFAULT_SOURCE

所以如果你添加

#define _DEFAULT_SOURCE

在包含任何标准C头文件之前,它适用于onlinegdb.com 和ideone.com。

所以代码应该是:

#define _DEFAULT_SOURCE   // <-- important
#include <stdio.h>
#include <string.h>

int main()
{
  char string[13];
  char *found, *cp = string;

  fprintf(stderr, "\nEnter string: ");
  scanf("%12s",string);
  printf("Original string: '%s'\n",string);

  while((found =  strsep(&cp,"/,-")) != NULL )
    {
    printf("Test 1"); /*To pinpoint where the seg fault arises*/
    printf("%s\n",found);
    }

  return(0);
}

请参阅: