Robert Benedict
Robert Benedict

Reputation: 45

Amount of memory to allocate to array of strings?

I have a char** which is designed to hold and unknown amount of strings with unknown length

I've initially allocated 10 bytes using

char **array = malloc(10);

and similarly, before adding strings to this array, I allocate

array[num] = malloc(strlen(source)+1)

I've noticed that my program crashes upon adding the 6th element to the array

My question is, how does memory with these arrays work? When I allocated 20 bytes, nothing happened, yet when I allocated 30, it suddenly could hold 10 elements. These were all strings of 2-3 characters in size. I'm struggling to think of a condition to realloc memory with, e.g

if condition{
    memoryofarray += x amount
    realloc(array, memoryofarray)
}

What exactly uses the memory in the char**? I was under the impression that each byte corresponds to how many lines they can hold, i.e. malloc(10) would allow the array to hold 10 strings. I need to know this to establish conditions + to know how much to increment the memory allocated to the array by.

Also, curiously, when I malloced

array[num] = malloc(0)

before assigning a string to that array element, it worked without problems. Don't you need to at least have strlen amount of bytes to store strings? This is confusing me massively

Upvotes: 1

Views: 1668

Answers (5)

chux
chux

Reputation: 154315

Rather than allocating memory using the fault-prone style

pointer = malloc(n); // or 
pointer = malloc(n * sizeof(type_of_pointer));

Use

pointer = malloc(sizeof *pointer * n);

Then

// Bad: certainly fails to allocate memory for 10 `char *` pointers
// char **array = malloc(10);

// Good
char **array = malloc(sizeof *array * 10);

how does memory with these arrays work?

If insufficient memory is allocated, it does not work. So step 1: allocate sufficient memory.

Concerning array[num] = malloc(0). An allocation of 0 may return NULL or a pointer to no writable memory or a pointer to some writable memory. Writing to that pointer memory is undefined behavior (UB) in any of the 3 cases. Code may crash, may "work", it is simply UB. Code must not attempt writing to that pointer.

To be clear: "worked without problems" does not mean code is correct. C is coding without a net. Should code do something wrong (UB), the language is not obliged to catch that error. So follow safe programming practices.

Upvotes: 1

Manos Nikolaidis
Manos Nikolaidis

Reputation: 22254

  1. This will allocate enough memory for 10 pointers to char (char*) in array

    char **array = malloc(10*sizeof(array[0]));
    

    On a 64bit system the size of a char* is 8 bytes = 64 bits. The size of a char is typically 1 byte = 8 bits.

  2. The advantage of using sizeof(array[0]) instead sizeof(char*) is that it's easier to change the type of array in the future.

  3. char** is pointer to a pointer to char. It may point to the start of a memory block in the heap with pointers to char. Similarly char* is a pointer to char and it may point to the start of a memory block of char on the heap.

  4. If you write beyond the allocated memory you get undefined behaviour. If you are lucky it may actually behave well! So when you do for example :

    array[num] = malloc(0);
    

    you may randomly not get a segmentation fault out of (good) luck.

  5. Your use of realloc is wrong. realloc may have to move the memory block whose size you want to increase in which case it will return a new pointer. Use it like this :

    if (condition) {
        memoryofarray += amount;
        array = realloc(array, memoryofarray);
    }
    

Upvotes: 2

ameyCU
ameyCU

Reputation: 16607

If you want to hold 10 strings then you need to allocate memory for 10 char *'s and then allocate memory to those char pointers .You allocate memory of 10 bytes( not enough for 10 char *'s ) .Allocate like this -

char **array = malloc(10*sizeof(char *));   // allocate memory for 10 char *'s

And then do what you were doing -

array[num] = malloc(strlen(source)+1)    // allocate desired memory to each pointer

note - take care that num is initialized and does not access out of bound index.

Upvotes: 2

Lundin
Lundin

Reputation: 214300

First allocate an array of pointers:

char* (*array)[n] = malloc( sizeof(*array) );

Then for each item in the array, allocate the variable-length strings individually:

for(size_t i=0; i<n; i++)
{
  (*array)[i] = malloc( some_string_length );
}

Upvotes: 0

SirDarius
SirDarius

Reputation: 42949

This line:

char **array = malloc(10);

allocates 10 bytes, however, remember that a pointer is not the same size as a byte.

Therefore you need to make sure you allocate an array of sufficient size by using the size of the related type:

char **array = malloc(10 * sizeof(char*));

Now that you have an array of 10 pointers you need to allocate memory for each of the 10 strings, e.g.

array[0] = malloc(25 * sizeof(char));

Here sizeof(char) is not needed but I added it to make it more obvious how malloc works.

Upvotes: 3

Related Questions