Pointers in structure with dynamic memory allocation - c

I am attempting to create a structure (2nd) in a structure (1st) with dynamic memory allocation. For the sequence of steps below (case 1), where I call malloc for a pointer to the 2nd structure before calling realloc for the 1st structure, I see garbage when printing the value of the member (str[0].a1) in the first structure. If I place the same realloc code before malloc (case 2), there are no issues.
#include<stdio.h>
#include<stdlib.h>
typedef struct string2_t {
int a2;
} string2;
typedef struct string1_t {
int a1;
string2 * b;
} string1;
string1 * str = NULL;
int size = 0;
string1 test(int val){
// case 2
//str = (string1 *) realloc(str, size*sizeof(string1));
string1 S;
S.a1 = val;
size += 1;
S.b = (string2 *) malloc(2*sizeof(string2));
S.b[0].a2 = 11;
S.b[1].a2 = 12;
// case1
str = (string1 *) realloc(str, size*sizeof(string1));
return S;
}
int main() {
size += 1;
str = (string1 *) malloc(size*sizeof(string1));
str[0] = test(10);
printf("value of a:%d\n",str[0].a1);
str[1] = test(20);
printf("value of a:%d\n",str[0].a1);
return(0);
}
I can see that memory location changes for case 1, but I don't quite understand why doesn't pointer point to the right contents (str[0].a1 shows junk). I haven't returned the address of 1st structure before realloc, so I feel it should have worked. Could someone explain why it's pointing to garbage?

As has been stated by several in the comments, lines like this cause undefined behavior:
str[0] = test(10);
The test() function reallocates str, and this is not sequenced with retrieving the address of str[0] as the location to store the result. It's very likely to be compiled as if it had been written
string1 *temp = str;
temp[0] = test(10);
temp caches the old address of str from before the realloc(), and this is invalid after the function returns.
Change your code to:
string1 temp = test(10);
str[0] = temp;
Better design would be to reorganize the code so that all maintenance of the str array is done in one place. test() should be a black box that just allocates the string1 object, while main() allocates and reallocates str when assigning to it.

Related

is this correct use of pointer and memory allocation

so This is my code that allocate 0th and 2ed string in 2-d array (list of strings, or a bucket) So I like to know did I use correct use of dynamic memory allocation with malloc and realloc.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char **a;
printf("%zu\n",sizeof(*a));
a = malloc(sizeof(*a)*3);
a[0] = malloc(sizeof(char ) * 10);
strcpy(a[0],"hello");
printf("%s\n",a[0]);
a[2] = malloc(sizeof(char) * 12);
strcpy(a[2],"hello hello");
printf("%s\n",a[2]);
a[0] = realloc(a[0],18);
strcpy(a[0],"hello hello hello");
printf("%s\n",a[0]);
return 0;
}
I like to knw can I jump from 0th string allocation to 2ed string allocation. is is valid in C/C++
Like first I did
a[0] = malloc(sizeof(char ) * 10);
then
a[2] = malloc(sizeof(char) * 12);
missing 1st index allocation like
a[1] = malloc(sizeof(char) * 12);//didnt do
In general the code is unsafe because the second element stays uninitialized.
At least you should write
a[1] = NULL;
For example this allows to free the allocated memory in a loop.
for ( size_t i = 0; i < 3; i++ )
{
free( a[i] );
}
free( a );
Also this statement
a[0] = realloc(a[0],18);
is unsafe. You need to use an intermediate pointer like for example
char *tmp = realloc(a[0],18);
if ( tmp ) a[0] = tmp;
Otherwise a memory leak can occur if the allocation will fail.
And in any case you should check whether allocations were successful.

Attempting to free address that was not malloced , error on realloc

Question : https://leetcode.com/problems/find-and-replace-in-string/
"""
char * findReplaceString(char * s, int* indices, int indicesSize, char ** sources, int
sourcesSize, char ** targets, int targetsSize){
int len = strlen(s);
char *copyS;
char *copy = (char*) malloc(sizeof(char)*len);
memcpy(copy, s, sizeof(char)*len);
copyS = copy;
int x = indicesSize-1;
int indexArr[1001] = {0};
int y;
for(int j=0; j<indicesSize; j++)
{
indexArr[indices[j]] = j;
}
qsort(indices, indicesSize, sizeof(int), cmp);
while((x >= 0))
{
y = indexArr[indices[x]];
copy = copyS+(indices[x]);
if(!(strncmp(copy, sources[y], strlen(sources[y]))))
{
copy = (char *)realloc(copy, sizeof(char)*(sizeof(copy) + sizeof(targets[y])));
strcpy(copy, targets[y]);
}
x--;
}
return copyS;
}
I am getting a runtime error due to the use of realloc. I was trying to modify the input string 's'. Got a runtime error due to realloc: Trying to free memory that was not malloced.
So I malloced new string pointer , *copy. Still getting same error when I use realloc on copy
There are several problems with the code.
For starters it is unclear whether the dynamically allocated array pointed to by the pointer copy shall contain a string or not.
If it shall contain a string then instead of
char *copy = (char*) malloc(sizeof(char)*len);
memcpy(copy, s, sizeof(char)*len);
you need to write
char *copy = (char*) malloc(sizeof(char)*( len + 1 ));
memcpy(copy, s, sizeof(char)*( len + 1 ));
Also it is unclear why there is used the magic number 1001 in this declaration
int indexArr[1001] = {0};
The pointer copyS was assigned with the address of the initially allocated memory
char *copyS;
char *copy = (char*) malloc(sizeof(char)*len);
memcpy(copy, s, sizeof(char)*len);
copyS = copy;
but then you are trying to reallocate the memory
copy = (char *)realloc(copy, sizeof(char)*(sizeof(copy) + sizeof(targets[y])));
As a result the pointer copyS can have an invalid value. And this pointer with an invalid value is returned from the function
return copyS
In turn the pointer copy is changed within the while loop
while((x >= 0))
{
y = indexArr[indices[x]];
copy = copyS+(indices[x]);
//..
So after such an assignment it does not point to the previously allocated memory extent. Hence using the pointer in the call of realloc
copy = (char *)realloc(copy, sizeof(char)*(sizeof(copy) + sizeof(targets[y])));
invokes undefined behavior.
And again this statement
copy = copyS+(indices[x]);
also invokes undefined behavior because after the memory reallocation the pointer copyS can be invalid.
Once you do this
copy = copyS+(indices[x]);
you can no longer use 'copy' as an argument to realloc or free. The pointer you pass to these functions must be the value returned by a prior malloc or realloc (or calloc)
Save the original 'copy' in a variable like 'originalCopy'

Adding space before the memory block rather than after it using realloc in C

I have allocated an array of chars and I want to add another char at the beginning of the array while maintaining the order.
Ex. If pointer points to the beginning of 4 char blocks: A,B,C,D -> pointer[0]==A . If I add E the block of memory should look: E,A,B,C,D -> pointer[0]==E.
Additionally I want to do it in one line, without manually copying elements to another block and erasing the first. All functions have to be from C standard library.
I have though of something like pointer = realloc(pointer-1, (n-1)*size), but I'm not guaranteed that pointer-1 is free.
Thankful for your answers in advance
Adding space before the memory block rather than after it using realloc
Re-allocate with realloc() and then shift the data with memove().
I want to do it in one line,
Either use a helper function like below or employ a long hard to read un-maintainable line.
char *realloc_one_more_in_front(char *ptr, size_t current_size) {
void *new_ptr = realloc(ptr, sizeof *ptr * (current_size + 1));
if (new_ptr == NULL) {
return NULL; // Failure to re-allocate.
}
ptr = new_ptr;
memmove(ptr + 1, ptr, sizeof *ptr * current_size);
return ptr;
}
Sample usage. For simplicity of example, error handling omitted.
size_t current_size = 4;
char *ptr = malloc(current_size);
for (size_t i = 0 ; i<current_size; i++) {
ptr[i] = 'A' + i;
}
ptr = realloc_one_more_in_front(ptr, current_size++);
ptr[0] = 'E';
printf("%.*s\n", (int) current_size, ptr);

Swapping 2 elements in an array of pointers (to strings of different length) in C

I am trying to swap 2 elements in an array of pointers, and these pointers point to strings of different length. Another function handled allocating memory to the array and the strings, the swap function will simple take an char** array and swap the elements I need to swap. What I am wondering is when I swap the pointers, is the allocated memory for each string retained when I swap or does this get messed up?
This isn't my exact code from my project, but what it's doing is identical:
int main() {
char** array = malloc(10 * sizeof(char*));
char* a = (char*)malloc(4*sizeof(char*));
char* b = (char*)malloc(14*sizeof(char*));
a = "test";
b = "this is a test";
array[0] = a;
array[1] = b;
char*temp;
temp = array[0];
array[0] = array[1];
array[1] = temp;
free[array];
free[a];
free[b];
return 0;
}
Too summarize, my question is in regard to the allocated memory of a and b. Is that allocated memory still correct/fine after the swap?
The swap is fine. The problem is how you are allocing memory for the a and b pointers and how you are assigning strings to them. And no, when you use the swap algorithm the blocks of memory won't be scrambled. If you do not change a and b, then you will be fine (which you are doing). In C, things work like this:
char *a = malloc(4 * sizeof(char));
a = "test"; // this is an error, and you will lose the memory block
This is allocating 4 units of memory, each unit is of the size of a char. When you do:
char *a = malloc(4 * sizeof(char**));
This is allocating 4 units of memory, each unit is of the size of char *, or a pointer to char. This is not what you intended. Furthermore, if you want to put a string in a pointer to char, you should use the strncpy function (or strndup if available).
char *a = malloc(5 * sizeof(char)); // always alloc space for the NULL byte
strncpy(a, "test", 4);
char *b = strndup("test", 4);
free(a);
free(b);
Note that you did alloc the memory for the array of pointers in the right way, doing:
char **array = malloc(10 * sizeof(char*));
... will give you a block of 10 units of memory, each of which are of the size of char *. Then you can address each of those units of memory by indexing the array pointer.
Couple pointers (no pun): first, you don't need to cast the return of malloc. Second, you don't need to multiply by sizeof(char). Bellow is a little working version of the code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char **array = malloc(10 * sizeof(char*));
char *a = malloc(5);
char *b = malloc(15);
strcpy(a, "test");
strcpy(b, "this is a test");
char *temp;
array[0] = a;
array[1] = b;
// prints "test" then "this is a test"
printf("%s\n%s\n\n", array[0], array[1]);
// this swaps them
temp = array[0];
array[0] = array[1];
array[1] = temp;
// now it prints "this is a test" and "test"
printf("%s\n%s\n\n", array[0], array[1]);
free(a);
free(b);
free(array);
}

Why my C code got error in Windows? Linux is ok

There is my C code, it is a leetcode problem, and I got "Runtime Error". So I recompile in VS2013, the problem is free(++tmp), why? I can't get it, I writen C code like that, just want to known more things about pointer.
#include <stdio.h>
#include <stdlib.h>
/* Add binary.
* a = "11", b = "1"
* result = "100"
*/
char *add_binary(char *a, char *b);
int main()
{
printf("%s\n", add_binary("10", "1"));
printf("%s\n", add_binary("1111", "1111"));
return 0;
}
char *add_binary(char *a, char *b)
{
int alen = 0, blen = 0, sum = 0;
int len;
char *tmp, *result;
while(*a++) alen++;
while(*b++) blen++;
a -= 2;
b -= 2;
len = alen > blen ? alen : blen;
tmp = (char *)malloc(len*sizeof(char));
printf("%p\n", tmp);
while(*a || *b){
if(*a){
sum += *a - '0' + 0;
a--;
}
if(*b){
sum += *b - '0' + 0;
b--;
}
if(sum > 1){
*tmp++ = 3 == sum ? '1' : '0';
sum = 1;
} else {
*tmp++ = 1 == sum ? '1' : '0';
sum = 0;
}
}
*tmp = '\0';
len += 1 == sum ? 1 : 0;
result = (char *)malloc(len*sizeof(char));
if(1 == sum){
*result++ = '1';
}
while(*(--tmp)){
*result++ = *tmp;
}
*result = '\0';
printf("%p\n", tmp);
free(++tmp);
tmp = NULL;
return (result-len);
}
You can only pass to free the resulting pointer value of malloc:
tmp = (char *)malloc(len*sizeof(char));
then
free(tmp);
is OK.
But free(++tmp) or free(tmp + 42) is not OK and invokes undefined behavior.
Stop modifying the mallocated pointer before freeing it. If you want to use pointer arithmetic, eg '*tmp++', then keep a copy of the original so that the space can be freed.
I have no clue why you would do 'free(++tmp);'. It makes no sense though, by that time, you've already totally shagged up tmp by incrementing it in the while loop:(
Edit: BTW, you've screwed 'result' as well. You are returning a malloced and bodged pointer that cannot be correctly freed by the caller.
Whatever 'clever' thing you are attempting with the pointer manipulations, stop it. It's too easy to get it wrong!
Here is a slightly more detailed response from the other answer.
The pointer is an address for which you allocate memory. When you pass in an address to free that has been previously malloc'd there is no problem. The problem is that you are not passing in the address of a malloc'd space. You are passing in the address of something that is potentially within a malloc'd space and as such cannot be freed.
free expects its argument to be the same pointer value that was returned from a previous malloc or realloc call. If you modify that pointer value before passing it to free, then the behavior is undefined and Bad Things can happen (this is why it appears to work for one platform and breaks on another; in truth, it's broken for both).
You'll need to preserve the pointer values returned from your malloc calls:
char *tmp, *tmpOrig;
...
tmp = tmpOrig = malloc(len * sizeof *tmpOrig); // note no cast, operand of sizeof
...
/**
* modify tmp to your heart's desire
*/
...
free( tmpOrig );
You'll need to do the same thing for result.
You should not cast the result of malloc, unless you are working with a pre-C89 compiler. It's unnecessary, and under C89/C90 compilers can mask a bug.

Resources