C realloc not changing apparent size of character array - c

When I run the below code, I get the given output.
#include <stdio.h> /* printf */
#include <stdlib.h> /* malloc, realloc */
int main()
{
char* characters = (char *) malloc(10 * sizeof(char));
printf("Before: characters at %p, size=%lu\n", (void *) characters, sizeof(characters) / sizeof(characters[0]));
char* temp = (char *) realloc(characters, 100);
if (temp)
{
printf("After realloc, characters size = %lu, temp size = %lu\n", sizeof(characters) / sizeof(characters[0]), sizeof(temp) / sizeof(temp[0]));
printf("After realloc, nums at %p, temp at %p\n", (void *) characters, (void *) temp);
//characters = temp;
free(temp);
}
free(characters);
}
/* Output:
Before: characters at 0x107b00900, size=8
After realloc, characters size = 8, temp size = 8
After realloc, nums at 0x107b00900, temp at 0x107b00910
test(3556) malloc: *** error for object 0x107b00900: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Abort trap: 6
*/
I'm trying to figure out what is malfunctioning.
I think that malloc sets aside space for ten consecutive characters and gives me a pointer to the first element of that array, and I store that pointer in characters. I then print the size of characters, and I expect 10, but I get 8. That's the first weird thing. Then, I ask realloc to find a new spot in the heap, which has space for 100 consecutive characters and return to me a pointer to the first spot. I put that pointer into temp. When I print temp's size, I get 8 (again), even though I expect 100. When I print the pointers to characters and temp, I get two different locations in the heap. Usually, I would then reassign the characters pointer to point to whatever temp is pointing to. Then I tried to free my pointers, and it told me that it couldn't free 0x107b00900, the exact location characters is, because the object at that point wasn't malloced; however, I did malloc space for characters. Why is this happening? Am I misunderstanding the functionality of malloc, realloc, sizeof, or something else? Thank you for your help.

There is no way to find the actual size allocated by alloc/realloc. The trick with dividing the size of characters by size of *characters works only for arrays; it does not work for pointers.
The library does not keep track of the size of the allocated chunk of memory in a way that would be available to the users of the standard library. It may store some information for its own use, but there is no user-facing call to retrieve it.
A common way of working around this issue is to store the size of the allocation along with the pointer to the allocated area.

You can't use sizeof on your pointer to get the amount of memory allocated.
char* characters = (char *) malloc(10 * sizeof(char));
The characters variable does not know how much space it is pointing to. It's your job to keep track of it.
As far as
char* temp = (char *) realloc(characters, 100);
realloc can move the memory block - which is what happens here. When it does that it marks the memory originally pointed to by characters as unallocated. Thus, when you free characters on the last line, you get an error because you are freeing memory that the system has marked as unallocated.

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.

What is the difference between using strcpy and equating the addresses of strings?

I am not able to understand the difference between strcpy function and the method of equating the addresses of the strings using a pointer.The code given below would make my issue more clear. Any help would be appreciated.
//code to take input of strings in an array of pointers
#include <stdio.h>
#include <strings.h>
int main()
{
//suppose the array of pointers is of 10 elements
char *strings[10],string[50],*p;
int length;
//proper method to take inputs:
for(i=0;i<10;i++)
{
scanf(" %49[^\n]",string);
length = strlen(string);
p = (char *)malloc(length+1);
strcpy(p,string);//why use strcpy here instead of p = string
strings[i] = p; //why use this long way instead of writing directly strcpy(strings[i],string) by first defining malloc for strings[i]
}
return 0;
}
A short introduction into the magic of pointers:
char *strings[10],string[50],*p;
These are three variables with distinct types:
char *strings[10]; // an array of 10 pointers to char
char string[50]; // an array of 50 char
char *p; // a pointer to char
Then the followin is done (10 times):
scanf(" %49[^\n]",string);
Read C string from input and store it into string considering that a 0 terminator must fit in also.
length = strlen(string);
Count non-0 characters until 0 terminator is found and store in length.
p = (char *)malloc(length+1);
Allocate memory on heap with length + 1 (for 0 terminator) and store address of that memory in p. (malloc() might fail. A check if (p != NULL) wouldn't hurt.)
strcpy(p,string);//why use strcpy here instead of p = string
Copy C string in string to memory pointed in p. strcpy() copies until (inclusive) 0 terminator is found in source.
strings[i] = p;
Assign p (the pointer to memory) to strings[i]. (After assignment strings[i] points to the same memory than p. The assignment is a pointer assignment but not the assignment of the value to which is pointed.)
Why strcpy(p,string); instead of p = string:
The latter would assign address of string (the local variable, probably stored on stack) to p.
The address of allocated memory (with malloc()) would have been lost. (This introduces a memory leak - memory in heap which cannot be addressed by any pointer in code.)
p would now point to the local variable in string (for every iteration in for loop). Hence afterwards, all entries of strings[10] would point to string finally.
char *strings[10]---- --------->1.
strcpy(strings[i],string) ----->2.
strings[i] = string ----------->3.
p = (char *)malloc(length+1); -|
strcpy(p,string); |-> 4.
strings[i] = p;----------------|
strings is an array of pointers, each pointer must point to valid memory.
Will lead undefined behavior since strings[i] is not pointing to valid memory.
Works but every pointer of strings will point to same location thus each will have same contents.
Thus create the new memory first, copy the contents to it and assign that memory to strings[i]
strcpy copies a particular string into allocated memory. Assigning pointers doesn't actually copy the string, just sets the second pointer variable to the same value as the first.
strcpy(char *destination, char *source);
copies from source to destination until the function finds '\0'. This function is not secure and should not be used - try strncpy or strlcpy instead. You can find useful information about these two functions at https://linux.die.net/man/3/strncpy - check where your code is going to run in order to help you choose the best option.
In your code block you have this declaration
char *strings[10],string[50],*p;
This declares three pointers, but they are quite different. *p is an ordinary pointer, and must have space allocated for it (via malloc) before you can use it. string[50] is also a pointer, but of length 50 (characters, usually 1 byte) - and it's allocated on the function stack directly so you can use it right away (though the very first use of it should be to zero out the memory unless you've used a zeroing allocator like Solaris' calloc. Finally, *strings[10] is a double pointer - you have allocated an array of 10 pointers, each element of which (strings[1], strings[9] etc) must be allocated for before use.
The only one of those which you can assign to immediately is string, because the space is already allocated. Each of those pointers can be addressed via subscripts - but in each case you must ensure that you do not walk off the end otherwise you'll incur a SIGSEGV "segmentation violation" and your program will crash. Or at least, it should, but you might instead get merely weird results.
Finally, pointers allocated to must be freed manually otherwise you'll have memory leaks. Items allocated on the stack (string) do not need to be freed because the compiler handles that for you when the function ends.

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

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.

Resources