1

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

我发现并使用了:

#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);eg 的参数更改为printf("%i\n",found);我会返回一些随机性,但总是正确的数量,例如如果我输入1/2/3我会得到三行垃圾,输入1111/2222会给出两行。我尝试了 %c, %i, %d, %p 并且他们都做同样的事情,但是 %s 段错误。

我完全被难住了。

4

2 回答 2

4

段错误是因为您的while. 您将继续打印“Test 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
于 2018-03-20T21:32:37.117 回答
2

这就是问题:

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

并且您认为您printf在循环中同时执行了两个 s,但实际上这段代码相当于

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并发现了这个:

人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);
}

看:

于 2018-03-20T21:35:14.487 回答