3

Having this:

#define _DEFAULT_SOURCE 1
#include <stdio.h>
#include <string.h>

int main(){
    char *token, org[] = "Cats,Dogs,Mice,,,Dwarves,Elves:High,Elves:Wood";
    while((token=strsep(&org,",")))
        printf("Token: %s\n",token);
}

gives err (incompatible pointer type):

/usr/include/string.h:439:14: note: expected ‘char ** restrict’ but argument is of type ‘char (*)[47]’
 extern char *strsep (char **__restrict __stringp,
  1. I know it is different type (one has memory initialized -> org[], but the function wants pointer without any memory initialized), but they have the same behaviour, so why it complain anyway?

  2. And can somone explain me, what is the meaning of this keyword restrict or __restrict in case of *strsep (char **__restrict __stringp, (on the other hand, I assume the __stringp is not a internal datatype (because of double underscores) but only a fancy variable name).

Edit: I think an array is stored in stack, but the strsep wants a pointer that points to a heap, which could be done with having org allocated with malloc and then memcpy, or even better, copy the string via strdup (which does internally memcpy). But anyway, way does strsep wants pointer that points to heap and not to stack? Both are just pointers, point only to different addresses, but that should not mind.

milanHrabos
  • 2,010
  • 3
  • 11
  • 45

3 Answers3

2

The strsep function requires the address of a modifiable pointer as its first argument (or NULL, in which case it does nothing); you are passing it the (fixed) address of an array. You can fix this by declaring a separate char* variable and assigning to that the (address of the) org array:

int main()
{
    char* token, org[] = "Cats,Dogs,Mice,,,Dwarves,Elves:High,Elves:Wood";
    char* porg = org; // "porg" is a MODIFIABLE pointer initialized with the start address of the "org" array
    while ((token = strsep(&porg, ",")))
        printf("Token: %s\n", token);

    return 0;
}

From the Linux manual page (bolding mine):

If *stringp is NULL, the strsep() function returns NULL and does nothing else. Otherwise, this function finds the first token in the string *stringp, that is delimited by one of the bytes in the string delim. This token is terminated by overwriting the delimiter with a null byte ('\0'), and *stringp is updated to point past the token. In case no delimiter was found, the token is taken to be the entire string *stringp, and *stringp is made NULL.

On the meaning and use of the restrict keyword, maybe this will help: Realistic usage of the C99 'restrict' keyword?.

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
  • In what sense you refer *fix* address vs *modifiable* address? Both are just address. You car perform a pointer arithmetic on both of them. Can you please explain, what do you mean by *fixed* address? – milanHrabos Jun 21 '20 at 17:00
  • @milanHrabos `org` is an array declared in a function (`main`, in this case, but it could be *any* function). Normally, memory for such data (known as "automatic variables") is assigned on the stack, and the address of that data item is thus 'fixed' for the duration of the function in which it is defined. You can't change where that data is. Although arrays and pointers have some *syntactic* similarities, they are **not** the same thing. – Adrian Mole Jun 21 '20 at 17:14
  • I know only about args, that are passed to function, that thay no longer live after function return, but not about automatic vars. The reason for args is they are `push`ed onto the stack (on x32, x64 uses registers for args), and at the end of function, the stack pointer is `add`ed (so deleted the pushed args). Is that the case of `org`?, because `org` is not arg to function `main`. In generated assembly, I only see `leave` instruction, but not `adding` back stack pointer. That means I *can* access `org` address from stack *after* main returns, which makes it movable, not fixed – milanHrabos Jun 21 '20 at 17:25
  • my bad, just read https://stackoverflow.com/questions/29790175/assembly-x86-leave-instruction/29790275, where `leave` does excatly what I refered to `adding`, so now I see, the `org` cannot be access anymore, once the function returns. But anyway, why some function require to have modifiable (meaning anytime accessible) pointers, when they are called with the main function stack anyway (they are called inside main function, so they have access to stack), heap accessing is superfluous – milanHrabos Jun 21 '20 at 17:32
1

Address of the array references the place where the array starts, it has only the different type - pointer to the array. It is not pointer to pointer.

    char *token, org[] = "Cats,Dogs,Mice,,,Dwarves,Elves:High,Elves:Wood";
    char *pointer = org;
    while((token=strsep(&pointer,",")))
    /* ... */

You cant cast reference to array to double pointer.

restrict it a quite advanced topic. It promises the compiler that if the object referenced by pointer is modified, the access to this object can be only done by this pointer. It helps the compiler in the code optimisations

Generally speaking I would not expect you to use this qualifier before you get proficient in the C language.

0___________
  • 60,014
  • 4
  • 34
  • 74
  • so *only* if a object referenced by restrict pointer is modified, then the pointer is the only entry? How otherwise it could be modified, then with the pointer referencing that object? Can you please give a minimal example, where its usage is appropriate? – milanHrabos Jun 21 '20 at 14:27
0
#include <stdio.h>
#include <string.h>

int main()
{
    char org[] = "Cats,Dogs,Mice,,,Dwarves,Elves:High,Elves:Wood";
    char *token = strtok(org, ",");
    while (token != NULL) {
        printf("Token: %s\n", token);
        token = strtok(NULL, ",");
    }
}

I think you should take a look at this page : Restrict type qualifier

bekici
  • 68
  • 10
  • No, I do not want to use `strtok` function, If I would I would post a question with that function, please look at my post, where I am using `strsep` defined by `glibc`. This is offtopic – milanHrabos Jun 21 '20 at 14:21