Amount of memory to allocate to array of strings? - c

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

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.

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.

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.
The advantage of using sizeof(array[0]) instead sizeof(char*) is that it's easier to change the type of array in the future.
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.
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.
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);
}

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.

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 );
}

Related

How to free allocated memory to an array of pointers after assigning value?

A simple beginner's dilemma so it should be quickly apparent.
I am trying to free allocated memory from a variable inside of the array of char pointers
This throws no error:
array= malloc(1*sizeof(char *) + 1);
array[0] = malloc(2*sizeof(char *));
free(array[0]);
Yet if I add some value to it, I get an error:
array= malloc(2*sizeof(char *));
array[0] = malloc(2*sizeof(char *));
array[0] = "a";
free(array[0]);
(malloc: *** error for object 0x10......: pointer being freed was not allocated
malloc: *** set a breakpoint in malloc_error_break to debug)
How could this be explained and how to deal with this?
Assuming your array is to be a list of pointers to strings (each of which will take data such as the 2-character, "a"), then there are a couple of errors in your approach.
First, the array[0] (and other elements) should be allocated as sizeof(char) * 2 (not sizeof(char*) * 2) – that will give pointers to buffers that can each hold up to 2 characters (the a letter and the nul-terminator).
So:
array= malloc(2*sizeof(char *)); // An array of two char* pointers
array[0] = malloc(2*sizeof(char)); // One pointer to a 2-character buffer
//...
Then, when you want to assign a given string to one of the elements, use the strcpy function, as shown below. What your array[0] = "a"; line does is to replace the address of the allocated buffer with the address of the string literal – and, as you didn't allocate that, you can't free it (and you then can't even free your actual allocated buffer, as you've 'lost' its address).
//...
strcpy(array[0], "a"); // Copy the second argument's data to the first
// ... later on ...
free(array[0]); // This will now (still) work, as you didn't change the address
// ...
free(array); // And don't forget to free the array of pointers!
Note, also, that sizeof(char) is defined (by the C Standard) to be 1 byte, so you can omit that in the second line of the first snippet above (but you need it in the sizeof(char*) case – the size of a pointer will vary between platforms and compilers).
#Adrian Mole is totally correct, and I just want to add a few comments about string literal.
String literal constants lie in the .rodata segment of the program, which is a pre-allocated, read-only segment occupying the program memory space. You cannot free or modify any value in this segment in any case, so
array[0] = "a";
array[0][0] = array[0][0] + 1;
will also cause an error.

Free the memory after it is allocated with calloc() to create an array of strings

After allocating memory with calloc() to create an array of strings, I want to try to free it and make sure that both strings and string pointers are permanently deleted.
The code is as follows
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argv) {
char **arr;
arr = calloc(3, sizeof(char *));
arr[0] = calloc(30, sizeof(char));
arr[1] = calloc(30, sizeof(char));
arr[2] = calloc(30, sizeof(char));
arr[0] = "jhgfdjhgfdjhgfds";
arr[1] = "oru95u9iojituy";
arr[2] = "hggpooki0opkopreiyh";
free(arr[2]); free(arr[1]); free(arr[0]);
//free(arr[0]); free(arr[1]); free(arr[2]);
free(arr);
}
As you can see in the end I tried to free up the memory allocated for strings. In the commented line I tried to free the memory in the opposite direction, believing that I had to follow the order in which the strings appeared in the array.
Despite this, I always get the following error:
free(): invalid pointer
I can't understand the problem. I know that each calloc () / malloc () must have its respective free (). It seems to be no memory address in arr [i], even though I called a calloc to it.
How can I go about freeing up the memory completely?
arr[0] = "jhgfdjhgfdjhgfds";
arr[1] = "oru95u9iojituy";
arr[2] = "hggpooki0opkopreiyh";
This isn't actually filling memory with string data, it's re-assigning and overwriting the pointers you just created with the calloc() call. String literals in C are themselves treated as pointers. If you want to initialize your pointers with the string data, use strcpy:
strcpy(arr[0], "jhgfdjhgfdjhgfds");
strcpy(arr[1], "oru95u9iojituy");
strcpy(arr[2], "hggpooki0opkopreiyh");
You're getting an error because the array elements no longer point to the memory that you allocated. The assignment
arr[0] = "jhgfdjhgfdjhgfds";
makes it point to the string literal instead.
You should use
strcpy(arr[0], "jhgfdjhgfdjhgfds");
to copy the literal string into the allocated memory (and similar for the other elements).
The problem is that the expression arr[0] = "jhgfdjhgfdjhgfds"; takes the address of the array of characters "jhgfdjhgfdjhgfds" and assigns it to the pointer stored in arr[0]. That overwrites the address of the buffer you allocated.
What you want to do is copy those letters into the memory pointed to by arr[0], i.e. the buffer that you allocated.
strcpy_s( arr[0], 30, "jhgfdjhgfdjhgfds" );
Note that you should really store that value 30 in a constant rather than repeating it throughout your code.

Cannot understand the meaning of two lines in C

This program reads a text file into a string array, line by line. I can't understand the meaning of two lines in the code:
char **words = (char **)malloc(sizeof(char*)*lines_allocated);
...
words = (char **)realloc(words,sizeof(char*)*new_size);
...
Please could you help me understand them?
char **words = (char **)malloc(sizeof(char*)*lines_allocated);
Allocates lines_allocated pointers. When you use pointer to pointers you need to allocate space for the pointers, and them for each of those pointers you allocate space for you data, in this case, a char *.
words = (char **)realloc(words,sizeof(char*)*new_size);
This changes the size of the buffer, as the number of lines is unknown before you read the file, then you need to increase the number of pointers you allocate.
words points to a block that will store lines_allocated pointers at first moment and then it will be increased to new_size when needed.
In your code you also have a line like this:
/* Allocate space for the next line */
words[i] = malloc(max_line_len);
Which will allocate each string separately.
Also, don't cast the result of malloc:
Do I cast the result of malloc?
The first line allocates a chunk of dynamic memory (creates space for an array of pointers to char); the second line resizes that chunk.
A better way to write both lines is
char **words = malloc( sizeof *words * lines_allocated); // no cast, operand of sizeof
char **tmp = realloc( words, sizeof *words * new_size );
if ( tmp )
words = tmp;
In C, you don't need to cast the result of either call, and it's considered bad practice to do so. Also, note the operand to sizeof; if you ever change the base type of words (from char to wchar_t, for example), you won't have to change the malloc or realloc calls.
realloc will return NULL if it can't extend the buffer, so it's safer to assign the result to a temporary variable first, otherwise you risk losing your reference to that memory, meaning you won't be able to access or release it.
The first line allocates a pointer to a pointer to character. A pointer to something in C is equivalent to a pointer to an array of that same something, so this is equivalent to saying that it allocates a pointer to an array of pointers to char.
sizeof(char*) is the size of a pointer, and multiplying it by lines_allocated means that the number of pointers in the allocated array will be lines_allocated.
The second line reallocates the array of pointers so that it may now contain new_size pointers instead of lines_allocated pointers. If new_size is larger, the new pointers will be undefined, and must be initialized before being used.

Is mallocing equivalent to pointer with a specified array size

I've read various tutorials on pointers, and I now come with a question,
is this:
char *input = malloc(sizeof(char)*24);
the same as
char *input[24];
I was under the impression that the malloc will also create my space on the heap with 24 slots. Usually, I see char input[24], but the char *input[24] I figured was a simpler way than mallocing.
Thanks!
No, they are not the same.
char *input = malloc(sizeof(char)*24);
will allocate a block of 24 char's on the heap and assign a pointer to the start of that block to input. (technically you are just telling it to allocate x number of bytes where x is 24 times the size, in bytes, of each char)
char *input[24];
will create an array of 24 char pointers on the stack. These pointers will not point to anything (or garbage on init) as you have it written.
For the second example, you could then take each pointer in the array input and allocate something for it to point to on the heap. Ex:
char *input[NUM_STRS];
for( int i = 0; i < NUM_STRS; i++ )
{
input[i] = malloc( MAX_STR_LEN * sizeof(char) );
}
Then you would have an array of character pointers on the stack. Each one of these pointers would point to a block of characters on the heap.
Keep in mind, however, that things on the stack will be popped off when the function exits and that variable goes out of scope. If you malloc something, that pointer will be valid until it is freed, but the same is not true of an array created on the stack.
EDIT:
Based on your comment, here is an example of making 24 character pointers on the heap and allocating space for them to point to:
#define NUM_STRS 24
#define MAX_STR_LEN 32
char **input = malloc( sizeof(char *) * NUM_STRS );
for( int i = 0; i < NUM_STRS; i++ )
{
input[i] = malloc( sizeof(char) * MAX_STR_LEN );
}
Please keep in mind that with this example you will have to free each pointer in input, and then input itself at the appropriate time to avoid leaking memory.
These are not the same at all.
char *input = malloc(sizeof(char)*24);
This allocates enough memory to hold 24 char, and assigns the address to input (a pointer). This memory is dynamically-allocated, so it needs to be released at some point with an appropriate call to free().
char *input[24];
This declares input to be an array of 24 pointers. This has automatic storage, which means you do not need to free it. (However, you may need to free the things being pointed to by each of the pointers, but that's a different matter!)
Fundamentally, the types of the two variables are different. In the first case, you declare a pointer to char that points to memory dynamically allocated by malloc (which you are morally obligated to free at a later instant). In the second case, you declare an array of pointers to char.
Couple of observations:
sizeof(char) is one by definition, so you can leave that out. (No, it does not convey a documenting purpose. You are better of rewriting it as char *input = malloc( 24 * sizeof *input );)
Very seldom will the call to malloc have an integer literal. If it does (24) in your example, then usually one would prefer to have an array to hold that (there are some considerations regarding stack usage that I am side-stepping here).
hope this helps,
You can compare it better to char input[24]; (note no *). With that you can use input in the same way but the memory is on the stack instead of on the heap.

How to get the size of dynamically allocated 2d array

I have dynamically allocated 2D array.
Here is the code
int **arrofptr ;
arrofptr = (int **)malloc(sizeof(int *) * 2);
arrofptr[0] = (int *)malloc(sizeof(int)*6144);
arrofptr[1] = (int *)malloc(sizeof(int)*4800);
Now i have to know that how many bytes are allocated in arrofptr,arrofptr[0],arrofptr[1]?
is there any way to know the size?
if we will print
sizeof(arrofptr);
sizeof(arrofptr[0]);
sizeof(arrofptr[1]);
then it will print 4.
You can't find size of arrofptr, because it is only a pointer to pointer. You are defining an array of arrays using that. There's no way to tell the size information with only a pointer, you need to maintain the size information yourself.
The only return value you get from malloc() is a pointer to the first byte of the allocated region (or NULL on failure). There is no portable, standard, way of getting the associated allocation size from such a pointer, so in general the answer is no.
The C way is to represent arrays and buffers in general with a pair of values: a base address and a size. The latter is typically of the type size_t, the same as the argument to malloc(), by the way.
if you want to keep track of the size of an allocated block of code you would need to store that information in the memory block that you allocate e.g.
// allocate 1000 ints plus one int to store size
int* p = malloc(1000*sizeof(int) + sizeof(int));
*p = (int)(1000*sizeof(int));
p += sizeof(int);
...
void foo(int *p)
{
if (p)
{
--p;
printf( "p size is %d bytes", *p );
}
}
alt. put in a struct
struct
{
int size;
int *array;
} s;
You can't get the length of dynamically allocated arrays in C (2D or otherwise). If you need that information save it to a variable (or at least a way to calculate it) when the memory is initially allocated and pass the pointer to the memory and the size of the memory around together.
In your test case above sizeof is returning the size of the pointer, and thus your calculation the size of the pointers is usually 4, this is why you got 4 and is likely to have the trivial result of 4, always.

Resources