-2

Here I try to get token from a string, separating by space. But I'm getting the segmentation fault if I run this program without while loop. It is fine, but why?


My code:

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

int main()
{
    char c[1000];
    int tnum, a, b, d;
    char *n;
    scanf("%d", &tnum);
    while(tnum != 0)
    {
        scanf("%[^\n]s", c);

        n = strtok(c, " ");
        a = atoi(n);

        n = strtok(NULL, " ");
        b = atoi(n);

        n = strtok(NULL, " ");
        d = atoi(n);

        printf("%d\n", a * b * d);
        tnum--;
    }
    return 0;
}
J...S
  • 5,079
  • 1
  • 20
  • 35
  • 1
    What input do you feed the program? And on what line do you get a segfault? (use a debugger to find out) – klutt Jul 31 '18 at 05:24
  • 2
    Note that a scan set is complete at the `]` of the `%[…]` format specification. The `s` is a literal character in the format that will not normally match anything, but you won't know that (there's no way for `scanf()` to report that problem). You're almost certainly getting a segmentation fault because `strtok()` is returning a null pointer when you aren't expecting it to. You should check that the `scanf()` calls are successful, and you should check that the `strtok()` calls are successful too, – Jonathan Leffler Jul 31 '18 at 05:26
  • 1
    `scanf("%[^\n]s",c);` --> `scanf(" %[^\n]", c);` should solve your issue. That being said, check the results of `scanf` and `strtok` as [Jonathan Leffler said](https://stackoverflow.com/questions/51605813/what-is-a-segmentation-fault-and-why-is-this-programme-showing-a-segmentation-fa#comment90177205_51605813) – Spikatrix Jul 31 '18 at 05:45
  • related: https://stackoverflow.com/questions/2346806/what-is-a-segmentation-fault – Kami Kaze Jul 31 '18 at 06:13
  • `%[^\n]s` requires an 's' at the end of the string being inputed? Is that intentional? Know that `%[]` and `%s` are different specifiers. – StoryTeller - Unslander Monica Jul 31 '18 at 06:58
  • Possible duplicate of [What is a segmentation fault?](https://stackoverflow.com/questions/2346806/what-is-a-segmentation-fault) – Chris Turner Jul 31 '18 at 09:29

1 Answers1

0

A segmentation fault is usually caused when the program tries to access memory which it is not allowed to use. Read What is a segmentation fault?.

In your case it might be caused because of the way you use the character array c[] and the strtok() function.

strtok() modifies its first argument based on the delimiters which are in the form of its second argument.

For example, if you do

char s[]="hello world how are you?";
strtok(s, " ");
printf("\n%s", s);

the output would be just

hello

and not

hello world how are you?

because the position with the delimiter is overwritten.This is a reason why strtok() can't be used on string literals.

The reason why you don't get error when you try without the while loop may be because c[] has a few spaces in the part of memory that the program is allowed to access. strtok() will go on looking for delimiters till the \0 denoting end of string is found which may be anywhere since c[] has garbage.


You haven't initialised c[] and it just has some garbage value. And there may or may not be a (space) which the strtok() is to consider as delimiter within the space for 1000 characters that you set aside in c[]. And if there is no within this 1000 bytes, the strtok() would look beyond the bounds of the array c[] and may modify memory which the program is not allowed to access.

Note that with

scanf("%[^\n]s",c);

you are asking the program to read everything till a \n and then an 's'. The extra s is not necessary. Just '%[^\n]` would've done.

But scanf() is not suited for this as it could easily lead to overflow. Read Disadvantages of scanf. You could try fgets() instead like

if( fgets(c, sizeof(c), stdin)==NULL )
{
    //something went wrong.
}

fgets() returns NULL upon error.

but keep in mind that fgets() would read in the trailing \n as well. Read Removing trailing newline character from fgets input.

So, as suggested in that post, do something like

char *pos;
if( (pos=strchr(c, '\n'))!=NULL )
{
    *pos='\0';
}

to replace the \n with the nul character denoting the end of string.

Had you done

scanf("%[^\n]", c);

instead, the \n would've remained unconsumed in the input buffer which could cause trouble if not taken care of later.

You may also want to check out How to convert a string to integer in C as atoi() does not allow for proper error checking.

J...S
  • 5,079
  • 1
  • 20
  • 35