0

I want to test pass pointer by reference in C, below is my test code.

I expect the result to be: "World!", but after I executed, I found that the result is indeterminate.

void parse(char **p)
{
    char str[] = "Hello World!";

    char *token = strtok(str, " "); // token points to 'H'
    *p = strtok(NULL, " "); // *p (buf) points to 'W'

}

int main() 
{
    char *buf = (char*)malloc(20 * sizeof(char));

    buf = "How are you?";

    parse(&buf);

    printf("%s\n", buf);
}

My View:

(1) In main(): buf points to 'H' ("How are you?"'s first char 'H') (Suppose address of 'H' is 0x10)

(2) parse(&buf) makes pointer p points to buf (i.e. *p = buf = 0x10)

(3) After 2 times of strtok(), *p (buf) points to 'W' (Suppose address of 'W' is 0x20)

(4) Now, return to main(), buf points to 0x20


(5) I expect printf("%s\n", buf); should print "World!", but instead print something like "garbled text".

I have tried debugging, but I don't think I have mistaken anything above.

Can someone quell my doubts?

Thanks in advance.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
Learning
  • 13
  • 4
  • 1
    `buf = "How are you?";` should be `strcpy(buf, "How are you?");` – Barmar Oct 26 '22 at 19:39
  • 2
    The local array `str`, and any pointers to it, become invalid when `parse()` returns. So your `printf()` causes undefined behavior. – Barmar Oct 26 '22 at 19:40
  • @Barmar (According to first comment) Yes, I also have tried this, but this is not the main problem causing unexpected results. – Learning Oct 26 '22 at 19:40
  • `*p = strtok(NULL, " ");` replaces where `buf` is pointing to, it does not copy the content. – Pablo Oct 26 '22 at 19:41
  • @Pablo He knows that, see the comment next to it.' – Barmar Oct 26 '22 at 19:42
  • 2
    There's so much of this code that makes no sense. Why do you bother allocating memory for `buf` if you're going to reassign it, first with `buf = "How are you?"` and again with `parse(&buf)`. You have a memory leak because you can't `free()` the memory you allocated. Why is `parse()` parsing a local string instead of the string that was passed to it? – Barmar Oct 26 '22 at 19:46
  • @Barmar I see! Sounds like I should `strcpy()` the contents of local string variable `str` before returning to `main()`, Thanks! – Learning Oct 26 '22 at 19:50
  • Yes. See https://stackoverflow.com/questions/11656532/returning-an-array-using-c – Barmar Oct 26 '22 at 19:54

1 Answers1

1

This code snippet

char *buf = (char*)malloc(20 * sizeof(char));

buf = "How are you?";

produces a memory leak.

At first memory was dynamically allocated and its address was assigned to the pointer buf and then the pointer was reassigned with the address of the first character of a string literal. As a result the address of the allocated memory was lost.

Also you may not change a string literal. Any attempt to change a string literal results in undefined behavior,

You should write at least

strcpy( buf, "How are you?" );

As for the function then its local array with automatic storage duration

void parse(char **p)
{
    char str[] = "Hello World!";
    //...

will not be alive after exiting the function. So the pointer buf will have an invalid value.

The program can look for example the following way

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

void parse( char *s, char **p)
{
    *p = strtok( s, " " );
    *p = strtok(NULL, " ");
}

int main() 
{
    char str[] = "Hello World!";

    char *buf;

    parse( str, &buf );

    if ( buf ) printf("%s\n", buf);
}
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • Because this is a test code, just testing how pass by reference in C works, so I try to simplify the code and ignore the memory leak problem, and indeed the main issue is local variables lifetime. Thanks – Learning Oct 26 '22 at 20:12
  • @Learning: actually `buf = "How are you?";` is a problem you must fix: `buf` points to a string literal, which is constant and must not be modified. `char buf[] = "Hello World!";` creates a local array `buf` initialized with a copy of the string literal, that can be modified by the `parse` function as a side effect of calling `strtok()`. A good exercice to understand how `strtok()` works is to re-write it. – chqrlie Oct 26 '22 at 20:33