1

Okay, imagine I have a char**, would this be the correct way to allocate memory? I mean: allocate memory for the char** itself and then for each char*...

char** fraseUsuario = NULL;
int length = 100, i = 0;

fraseUsuario = (char **) malloc(sizeof (char*)); //Not pretty sure

for (i = 0; i < 3; i++) {

    fraseUsuario[i] = (char *) malloc(length * sizeof (char));

    if (fraseUsuario[i] == NULL) {
        printf("error\n");
        return -1;
    }

    gets(fraseUsuario[i]);

}

for (i = 0; i < 3; i++) {
    printf("%s\n",  fraseUsuario[i]);
    free(fraseUsuario[i]);
}

And btw, how exactly does free() work? I mean, when I call it at the end, with the debugger it seems as if it does "nothing", if "Hello" is stored in the array, it will continue to be stored there after the free call... is that the normal behavior?

Alex Churchill
  • 4,887
  • 5
  • 30
  • 42
user3263115
  • 33
  • 1
  • 7
  • 3
    First of all, [do not cast the result of `malloc`](http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc). – pzaenger Feb 25 '14 at 17:03

2 Answers2

1

What do you mean allocate memory for the char ** itself? You allocate memory for a variable on the stack when you define it. The following statement defines (allocates memory) fraserUsuario and initializes it to NULL.

char **fraseUsuario = NULL;

I think what you probably meant is how to dynamically allocate an array of char **, i.e., pointer to a pointer to a character. Then you again dynamically allocate an array for each element of the previous allocated array. Do not use gets. It's deprecated and unsafe to use. Use fgets instead. Also, please don't cast the result of malloc. You don't get any benefit and you can run into error if you forget to include the header stdlib.h which contains its prototype. Here's how you do it.

char **fraseUsuario = NULL;
int max_string_len = 100 + 1;  // maximum string length. +1 for null byte
int num_string = 3;            // number of strings to read
int i, j;

fraseUsuario = malloc(num_string * sizeof *fraseUsuario);
if(fraseUsuario == NULL) {     // check for NULL
    // handle the case
    printf("not enough memory\n");
    return -1;
}

for(i = 0; i < num_string; i++) {
    fraseUsuario[i] = malloc(max_string_len * sizeof(char));
    if(fraseUsuario[i] == NULL) {     // check for NULL
        printf("not enough memory\n");
        for(j = 0; j < i; j++)
            free(fraseUsuario[j]);    // free memory before returning
        free(fraseUsuario);           // free memory before returning
        return -1;
    }
    if(fgets(fraserUsuario[i], max_string_len, stdin) == NULL) {
        // reading string failed
        *fraserUsuario[i] = '\0'; // empty string
    }
}

for(i = 0; i < 3; i++) {
    printf("%s\n", fraseUsuario[i]);
    free(fraseUsuario[i]);    // free memory allocated for strings
}
free(fraseUsuario);           // free memory allocated for pointers to strings 
fraseUsuario = NULL;   

When you call free on a memory address which you got by a call to malloc, the memory block is returned to the free pool on the heap. This memory block can then later be reused by malloc. Once you free memory, you have given up your ownership of it. It no longer belongs to you and attempting to use it is illegal and will result in undefined behaviour and likely segfault.

ajay
  • 9,402
  • 8
  • 44
  • 71
0

You only allocate memory for one char* but use three.

To fix this do:

#define STR_MAXIMUM (3)

...

size_t length = 100, i = 0; /* No need to use a signed type. 
                               size_t is meant as index and size type. */
char ** fraseUsuario = malloc(STR_MAXIMUM * sizeof(*fraseUsuario)); 

for (i = 0; i < STR_MAXIMUM; ++i) 
{
  fraseUsuario[i] = malloc(length * sizeof(*fraseUsuario));

    ...

Also add error checking to system calls.


Also^2: Do not use gets() as there is no way for the compiler or the machine to prevent the buffer passed in from overflowing. Use fgets() instead.

    fgets(fraseUsuario[i], length, stdin);
alk
  • 69,737
  • 10
  • 105
  • 255
  • and if, let's say, I don't know how many *char's I'm going to read, and I want to allocate a *char every iteration of the loop, I should do two mallocs? (one to allocate a *char and other for its length) – user3263115 Feb 25 '14 at 17:21
  • @user3263115 Have look at `realloc()` in case you need to re-size a previously allocated block of memory. – alk Feb 25 '14 at 17:28