0

When I pass a plain string to a function that returns single lines from that string and advances it to the next line, the function does not advance the string but overwrites it with the first line instead and loops endlessly.

char *consume_next_line(char *text_ptr)
{
    char *cursor = text_ptr;
    if (!*cursor)
        return NULL;

    char *line = cursor;

    while (*cursor && (*cursor != '\n'))
        ++cursor;

    char *end = cursor;

    if (*cursor) {
        ++end;
        if (*(cursor-1) == '\r')
            --cursor;
        *cursor = '\0';
    }

    text_ptr = end;

    return line;
}

int main(void)
{
    char *file_data = read_entire_file("main.c");

    int i = 0;
    char *line;

    while (line = consume_next_line(file_data)) {
        ++i;
        printf("%d: %s\n", i, line);
    }

    return 0;
}
1: int main(void)
2: int main(void)
3: int main(void)
...

When I pass the string as a pointer instead, it works fine (consume_next_line() and read_entire_file() are defined in a different file, this is an example).

char *consume_next_line(char **text_ptr)
{
    char *cursor = *text_ptr;
    if (!*cursor)
        return NULL;

    char *line = cursor;

    while (*cursor && (*cursor != '\n'))
        ++cursor;

    char *end = cursor;

    if (*cursor) {
        ++end;
        if (*(cursor-1) == '\r')
            --cursor;
        *cursor = '\0';
    }

    *text_ptr = end;

    return line;
}

int main(void)
{
    char *file_data = read_entire_file("main.c");

    int i = 0;
    char *line;

    while (line = consume_next_line(file_data)) {
        ++i;
        printf("%d: %s\n", i, line);
    }

    return 0;
}
1: int main(void)
2: {
3:     char *file_data = read_entire_file("main.c");
4: 
5:     int i = 0;
6:     char *line;
7: 
8:     while (line = consume_next_line(file_data)) {
9:         ++i;
10:         printf("%d: %s\n", i, line);
11:     }
12: 
13:     return 0;
14: }

I tested it with both GCC and MSVC and the result is the same. Why is that? Shouldn't both snippets work the same?

  • C doesn't have "strings". It has a `char` type, and a bunch of those in an array is a string. Arrays and pointers are two sides of the same coin in C. – Z4-tier Dec 17 '20 at 21:47
  • 1
    Function parameters are passed *by value* in C. Setting the parameter variable in a function only changes the local variable and does not change the caller's variable. So `text_ptr = end;` has no effect on the caller's `file_data` variable as you have found. `*text_ptr` on the other hand does reference the caller's variable. – kaylum Dec 17 '20 at 21:49
  • Thank you very much guys, I was stupid and just couldn't see it. Now it's clear. – durkadomida Dec 17 '20 at 21:51
  • It is mostly a language thing. IMHO `passing a string` is ambiguous. The speaker *could* mean: passing a pointer by reference. (eg : a pointer to pointer) BTW: even `string` is ambiguous, sometimes just the pointer is meant, sometimes the (string literal) object that it points to /my5cts – wildplasser Dec 17 '20 at 21:53

0 Answers0