0

I have sample code taken from Split string with delimiters in C

I found that if I comment out #include <string.h> the program builds, but crashes when I try to run it. Why does it crash?

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

char** str_split(char* a_str, const char a_delim)
{
    char** result    = 0;
    size_t count     = 0;
    char* tmp        = a_str;
    char* last_comma = 0;
    char delim[2];
    delim[0] = a_delim;
    delim[1] = 0;

    /* Count how many elements will be extracted. */
    while (*tmp)
    {
        if (a_delim == *tmp)
        {
            count++;
            last_comma = tmp;
        }
        tmp++;
    }

    /* Add space for trailing token. */
    count += last_comma < (a_str + strlen(a_str) - 1);

    /* Add space for terminating null string so caller
       knows where the list of returned strings ends. */
    count++;

    result = malloc(sizeof(char*) * count);

    if (result)
    {
        size_t idx  = 0;
        char* token = strtok(a_str, delim);

        while (token)
        {
            assert(idx < count);
            *(result + idx++) = strdup(token);
            token = strtok(0, delim);
        }
        assert(idx == count - 1);
        *(result + idx) = 0;
    }

    return result;
}

int main()
{
    char months[] = "JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC";
    char** tokens;

    printf("months=[%s]\n\n", months);

    tokens = str_split(months, ',');

    if (tokens)
    {
        int i;
        for (i = 0; *(tokens + i); i++)
        {
            printf("month=[%s]\n", *(tokens + i));
            free(*(tokens + i));
        }
        printf("\n");
        free(tokens);
    }

    return 0;
}
Community
  • 1
  • 1
vico
  • 17,051
  • 45
  • 159
  • 315
  • Don't know what this means: `I found that if I comment include programm crashes.`. – Fiddling Bits Dec 27 '13 at 18:07
  • 1
    @FiddlingBits If my interpretation is correct, it seems that the user is asking why the program posted will still compile (though it crashes) when `#include ` is commented out. – JAB Dec 27 '13 at 18:09
  • @JAB Yes, I think you're right. Thank you. – Fiddling Bits Dec 27 '13 at 18:11
  • *Where* does it crash? What line is causing the error? – John Bode Dec 27 '13 at 18:12
  • I get a compilation error when I comment out `#include `, which is expected. – Fiddling Bits Dec 27 '13 at 18:13
  • @FiddlingBits In that case, here's something unusual: http://ideone.com/RsyK4i Why does that still compile it properly? (Don't have a C compiler on my local machine to check here, unfortunately.) – JAB Dec 27 '13 at 18:14
  • @JAB It shouldn't… right? – Fiddling Bits Dec 27 '13 at 18:15
  • @FiddlingBits Right, which is why I was wondering why Ideone's C compiler does appear to compile it properly and not crash even with the `string.h` include commented out. – JAB Dec 27 '13 at 18:16
  • "*I found that if I comment out #include the program builds ...*" Does it build **without any** warnings? – alk Dec 27 '13 at 18:21
  • I'm pretty sure that OP is using Visual Studio with its phantom includes of everything everywhere :) – dreamzor Dec 27 '13 at 18:23

2 Answers2

2

If the code does not include <string.h> the return types for all functions used by the program which are prototyped in <string.h> will be assumed as int, which is 32bit.

If on a 64bit system this makes function returning pointers (which are 64bit) most probably fail miserably. This typically will be the case for strdup(), which would only return 32bits of a 64 address referencing the memory to hold the duplicated "string".

I clear hint for the case described above would be such a warning

warning: implicit declaration of function ‘strdup’

A warning issued by a C compiler is meant as what it is, a warning. Treat it as such.

alk
  • 69,737
  • 10
  • 105
  • 255
0

The <string.h> header contains the declarations of the standard string functions specified by the C standard (and possibly, depending on your settings, some additional non-standard functions like strdup(), which is defined by POSIX but not by C).

As of the 1990 ISO C standard, calling a function with no visible declaration is permitted, but the compiler will make certain assumptions about how that function is defined; in particular, it will assume that it returns an int result. If it's not actually defined that way, the call has undefined behavior. On some systems, calling a function that returns a char* as if it returned an int will appear to work; on others, it can fail in various horrible ways (which is actually better, because it makes it easier to find and correct the error).

One likely scenario is that the types int and char* have different sizes (for example, they're often 32 and 64 bits, respectively, on 64-bit systems). Or they might have the same size, but be returned from functions in different registers.

As of the 1999 standard, calling a function with no visible declaration is illegal (a constraint violation); the "implicit int" rule was dropped.

What that means is that any compiler that conforms to the C99 or later standard must issue a diagnostic message. In some cases, that diagnostic can be a warning, and the compiler can then go on to compile your program under the C90 rules -- or under any rules the compiler developers happened to choose.

If your compiler doesn't at least warn you about a call to strlen() when you haven't (directly or indirectly) included <stdio.h>, you should use whatever options your compiler supports to increase its warning level.

You can get away with ignoring warnings in some cases, but the safest practice is to treat compiler warnings as if they were fatal errors.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631