Theo Freeman
Theo Freeman

Reputation: 61

Why doesn't strsep() work with pointers to the stack?

It appears that there is a pointer compatibility problem using the function strsep to find the first word of a string. So far I always thought that char *s and char s[] are completely interchangeable. But it appears they are not. My program using an array on the stack fails with the message:

foo.c: In function ‘main’:
foo.c:9:21: warning: passing argument 1 of ‘strsep’ from incompatible pointer type [-Wincompatible-pointer-types]
  char *sub = strsep(&s2, " ");
                     ^
In file included from foo.c:2:0:
/usr/include/string.h:552:14: note: expected ‘char ** restrict’ but argument is of type ‘char (*)[200]’
 extern char *strsep (char **__restrict __stringp,

I do not understand the problem. The program using malloc works.

This works:

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

int main(void)
{
    char s1[] = "Hello world\0";
    char *s2 = malloc(strlen(s1)+1);
    strcpy(s2, s1);
    char *sub = strsep(&s2, " ");

    printf("%s\n", sub);

    return 0;
}

This doesn't:

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

int main(void)
{
    char s1[] = "Hello world\0";
    char s2[200];
    strcpy(s2, s1);
    char *sub = strsep(&s2, " ");

    printf("%s\n", sub);

    return 0;
}

What's the issue? (Sorry for strcpy). Why does it matter to functions wether a pointer points towards stack or heap? I understand why you can't access strings in the binary/text segment, but what's the issue with the stack?

Upvotes: 3

Views: 1074

Answers (2)

Unnamed_one
Unnamed_one

Reputation: 21

@DavidRankin is correct as to why it doesn't work. But you can still write code so it can use a variable on the stack.

To use an array in place of malloc(), you can create another pointer to the array and use that as your parameter to strsep() as shown in version1() function.

I know this may just be an example, but your provided example with malloc() and strsep() can lead to memory errors since strsep() will update the pointer (it modifies the address it points to). So you must save off the original address returned by malloc() in order to properly free that memory. See version2() example.

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


void version1(void)
{
    char s1[] = "Hello world";
    char s2[200];
    char* s3 = s2;
    char *sub;

    strcpy(s3, s1); // or s2 in place of s3

    while ((sub = strsep(&s3, " ")))
    {
        printf("%s\n", sub);
    }
}

void version2(void)
{
    char s1[] = "Hello world";
    char *mymem = malloc(strlen(s1)+1);
    char *s2 = mymem;
    char *sub;

    strcpy(s2, s1);

    while ((sub = strsep(&s2, " ")))
    {
        printf("%s\n", sub);
    }

    free(mymem);
}

int main(int argc, char* argv[])
{
    printf("Version1\n");
    version1();

    printf("\nVersion2\n");
    version2();

    return 0;
}

Upvotes: 2

David C. Rankin
David C. Rankin

Reputation: 84559

 note: expected ‘char ** restrict’ but argument is of type ‘char (*)[200]’

Your warning tells you exactly what the problem is. You have two different types.

char *s2;        /* declares a character pointer */

while

char s2[200];   /* declares an array of char[200] */

When you take the address of a pointer, the results is a pointer-to-pointer. When you take the address of an array, the results is a pointer-to-array. When you dereference a pointer-to-pointer, the result is a pointer. When you dereference a pointer-to-array, the result is an array.

strsep wasn't designed to take a pointer-to-array as an argument (which would prevent it from reallocating as needed)

Upvotes: 7

Related Questions