0

Something in my code is mysteriously replacing all the chars inside my const char *(the string upper, inside foo_add()) with garbage values. It seems to happen right after the call to malloc in foo_add(). I set breakpoints in Xcode inside the function, and upper is fine right before the malloc call, but filled with random values afterword. I'm a complete C newbie, so it's entirely possible there's something I'm doing that has some side effect I'm not aware of. I don't know if it's related to malloc or not, and I can't see why it would be. Code below. I added comments to show where the problem occurs.

//in Foo.h
#include <stdlib.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>

typedef struct Foo {
    struct Foo * members[26] ;
} Foo ;

const char * toUpper(const char * in) ;
const char * getSubstring(const char * str, size_t startingIndex) ;

void foo_init(Foo * f) ;
void foo_add(Foo * f, const char * str) ;

//in Foo.c
#include "Foo.h"

const char * toUpper(const char * in) {

    size_t length = strlen(in) ;
    char temp[length + 1] ;

    for (size_t i = 0 ; i < length; i++) {
        temp[i] = toupper(in[i]) ;
    }
    temp[length] = '\0' ;
    char * out = temp ;
    return out ;
}

const char * getSubstring(const char * str, size_t startingIndex) {
    size_t size = (unsigned)(strlen(str) - startingIndex) ;
    char temp[size + 1] ; //+1 for '\0' (terminating char)
    for (size_t i = 0 ; i < size ; i++) {
        temp[i] = str[i + startingIndex] ;
    }
    temp[size] = '\0' ;
    const char * ret = temp ;
    return ret ;
}

void foo_init(Foo * f) {
    for (size_t i = 0 ; i < 26 ; i++) {
        f->members[i] = NULL ;
    }
}

void foo_add(Foo * f, const char * str) {

    const char * upper = toUpper(str) ;
    int index = ((int)upper[0]) - 65 ;

    size_t length = strlen(str) ;
    if (length > 0) {
        if (f->members[index] == NULL) {
            /* debugger says upper = "ABCXYZ" here, which is expected */
            f->members[index] = (Foo *)malloc(sizeof(Foo)) ;
            /* set another debugger breakpoint here - upper is now filled with garbage values */
        }

        /* take substr and call recursively until length == 0 */
        const char * next = getSubstring(upper, 1) ;
        foo_add(f->members[index], next) ;
    }
}

//in main.c
#include <stdio.h>

#include "Foo.h"

int main(int argc, const char * argv[])
{
    Foo f ;
    foo_init(&f) ;

    const char * str = "abcxyz" ;

    foo_add(&f, str) ;
    return 0;
}
AdamJames
  • 367
  • 2
  • 11
  • `toUpper` returns the address of a local variable, the location pointed-to is invalid after returning. – mafso Jun 21 '14 at 01:03
  • This is not a duplicate... the other guy knew about the error and was asking why he didn't get a warning when compiled his code... this guy is asking why his code isn't working, which coincidently... the explanation to his mistake is exactly what that guy from the other question talked about @bgporter – nightshade Jun 21 '14 at 03:13

1 Answers1

1

The culprit is this code:

const char * function(const char * in) {
  char temp[..];
  char *out = temp;
  return out;
}

Here, temp is allocated on stack, not on heap. This means that its lifetime ends when the scope of the function exits. You should either allocate it dynamically on heap with, for example, char *temp = calloc(length+1, 1) or pass it from the called on a preallocated space (which could be on stack at that point).

Jack
  • 131,802
  • 30
  • 241
  • 343
  • You could add, that the same problem occurs in `getSubstring`… and yes, [it's](http://stackoverflow.com/questions/23875311/returning-array-of-int-in-c) [a](http://stackoverflow.com/questions/8743411/return-address-of-local-variable-in-c) [duplicate](http://stackoverflow.com/questions/6804176/returning-an-array-warning-function-returns-address-of-local-variable) […](http://stackoverflow.com/questions/8743411/return-address-of-local-variable-in-c) – mafso Jun 21 '14 at 01:09