String token from `strsep` not printing (seg fault)

南楼画角 提交于 2019-12-24 10:23:48

问题


I'm using with a smaller piece of code to test functionality for a larger (beginner) program, but I have a problem displaying the token I've pulled out of a string.

I found and used:

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

and this works fine, prints the tokens one at a time as strings.

Then when I try and move to a user entered string:

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

I get a seg fault on the printf("%s\n",found); line. I'm getting the hang of basics of pointers, arrays and strings, but clearly I'm missing something, and would love for someone to tell me what it is!

Also - if I change the argument of printf("%s\n",found); e.g. to printf("%i\n",found); I get some randomness returned, but always the correct amount, e.g. If I enter 1/2/3 I get three lines of junk, entering 1111/2222 gives two lines. I tried %c, %i, %d, %p and they all do the same, but %s seg faults.

I'm completely stumped.


回答1:


The segfault is because you're missing braces around your while. You'll keep printing "Test 1" until strsep returns NULL, then you try to print that result (and segfault).

With several warning flags (probably -Wall), gcc helps out here:

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);
     ^~~~~~

With braces added around the while, the program works as expected:

./sep 

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



回答2:


This is the problem:

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

and you think you are doing both printfs inside the loop, but in reality this code is equivalent to

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

that means, printf("%s\n",found); is basically doing printf("%s\n",NULL); which is undefined behaviour and may cause a segfault.

Note that in C indentation does not matter to the compiler. So you would need to use { and } around the code:

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

Doing that I get

$ ./a 

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

Also note that your first code is leaking memory, you are not freeing the allocated memory returned by strdup. You would have to save a pointer to that:

#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;
}

edit

Neither Stephen Newell nor me seems to have the same problem with the corrected version of the code. The OP provided a link to onlinegdb.com showing that the corrected version ends with a segfault.

I tried the same code on ideone.com and I also got the segfault. That seemed strange to me, so I opened my man page of strsep and found this:

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

The important part is this here: Since glibc 2.19: _DEFAULT_SOURCE

So if you add

#define _DEFAULT_SOURCE

before including any standard C header file, then it works on onlinegdb.com and ideone.com.

So the code should be:

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

See:

  • corrected onlinegdb.com version
  • corrected ideone.com version


来源:https://stackoverflow.com/questions/49394350/string-token-from-strsep-not-printing-seg-fault

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!