来自 `strsep` 的字符串标记未打印(段错误)
String token from `strsep` not printing (seg fault)
我正在使用一小段代码来测试较大(初学者)程序的功能,但我在显示从字符串中提取的令牌时遇到问题。
我发现并使用了:
#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 段错误。
我完全被难住了。
段错误是因为您缺少 while
周围的大括号。您将继续打印 "Test 1" 直到 strsep
returns 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
这是问题所在:
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;
}
编辑
和我似乎都没有同样的问题
代码的更正版本。 OP 提供了 link 到 onlinegdb.com
显示更正后的版本以段错误结尾。
我在 ideone.com 上尝试了相同的代码,但我也遇到了段错误。那似乎
对我来说很奇怪,所以我打开了 strsep
的手册页,发现了这个:
man strsep
SYNOPSIS
#include <string.h>
char *strsep(char **stringp, const char *delim);
Feature Test Macro Requirements for glibc (see 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);
}
参见:
我正在使用一小段代码来测试较大(初学者)程序的功能,但我在显示从字符串中提取的令牌时遇到问题。
我发现并使用了:
#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 段错误。
我完全被难住了。
段错误是因为您缺少 while
周围的大括号。您将继续打印 "Test 1" 直到 strsep
returns 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
这是问题所在:
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;
}
编辑
我在 ideone.com 上尝试了相同的代码,但我也遇到了段错误。那似乎
对我来说很奇怪,所以我打开了 strsep
的手册页,发现了这个:
man strsep
SYNOPSIS
#include <string.h> char *strsep(char **stringp, const char *delim);
Feature Test Macro Requirements for glibc (see 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);
}
参见: