pointer to pointer to structure with malloc and strdup - c

My main intention is to pass a pointer to a structure, to a function, which will allocate memory and fill all its values. After returning back i will print it on screen.
Structure looks like this.
struct isolock{
char *name;
unsigned int state;};
typedef struct isolock lock;
Please note i can not change declaration of this structure. My main function is very simple like this.
int main(){
int i = 0;
isolock *lock = NULL;
fillArray(&lock);
//print struct contents
for(i=0;(lock+i)->name;i++){
printf("name = %s status = %u \n", (lock+i)->name,(lock+i)->state);
}
}
fillArray function is suppose to allocate n + 1 memory blocks for my structure where n is the actual number of locks present. whereas last (n+1)th block will be filled with zero. So that while printing from main, i can just check for this condition, without need of worrying about length of structures which i have allocated.
My problem is in fillArray function.
static const char *array[] = {"SWMGMT_LOCK","OTHER_LOCK"};
void fillArray(isolock **dlock){
int i = 0;
if (*dlock == NULL){
*dlock = (isolock *)malloc((sizeof (*dlock)) * 3); //allocate space for holding 3 struct values
for(i=0;i<2;i++){
(*(dlock) + i)->name = strdup(array[i]);
(*(dlock) + i)->state = (unsigned int)(i+1);
}
(*(dlock) + i)->name = 0; //LINE100
(*(dlock) + i)->state = 0;
}
}
o/p:
name = status = 1
name = OTHER_FP_LOCK status = 2
Actually this LINE100 causes problem. It actually replaces already filled structure entry i.e., this line makes dlock[0]->name to be filled with 0. whereas dlock[1] remains unchanged.
My gdb log shows something like this.
All these are logs are taken after allocation and filling values.
(gdb) p (*(dlock)+0)
$10 = (isolock *) 0x804b008
(gdb) p (*(dlock)+1)
$11 = (isolock *) 0x804b010
(gdb) p (*(dlock)+2) <== Note here 1
$12 = (isolock *) 0x804b018
(gdb) p *(*(dlock)+0)
$13 = {name = 0x804b018 "SWMGMT_LOCK", state = 1} <== Note here 2
(gdb) p *(*(dlock)+1)
$14 = {name = 0x804b028 "OTHER_FP_LOCK", state = 2}
(gdb) n
33 (*(dlock) + i)->state = 0;
(gdb)
35 }
(gdb) p *(*(dlock)+2)
$15 = {name = 0x0, state = 0}
(gdb) p (*(dlock)+2)
$16 = (isolock *) 0x804b018
From note 1 and note 2 its very clear that, strdup has returned already allocated memory location by malloc i.e., first call to strdup has returned the address of dlock[2]. how could this happen. because of this, (*dlock+2)->name = 0 has caused dlock[0]->name to be filled with 0.
To easily explain this problem,
Malloc has returned me three addresses. for easy understanding lets say, {1000,1008,1010}
Two times i ve called strdup which has returned {1010,1018}
this 1010 and 1018 are stored in char *name of lock[0] and lock[1] respectively.
Can someone tell me, am i doing something wrong in this code or is this problem of strdup ( allocating a already allocated block of memory)
NOTE: When i have changed char *name to char name[20] and instead of strdup, i used strcpy and it worked perfectly.

A possible cause of the error is your allocation:
*dlock = (isolock *)malloc((sizeof (*dlock)) * 3);
Here dlock is a pointer to a pointer, so sizeof(*dlock) is the size of a pointer which is not the same as sizeof(struct isolock) (or sizeof(**dlock)).

Related

What happen if we allocate the memory to a same pointer twice using malloc in c?

This is my code:
there is array of size 5. and I allocating memory to the pointer p using malloc function.
here I want to know what happen after re-allocating the memory to same pointer and after
free the pointer than what happen. and when my if condition is true or when it's going to
execute.
int main()
{
int array[5] = {2, 5, 3, 10, 9};
int *p = (int*) malloc (sizeof (int));
*p = 5;
if (-1)
{
p = (int *)malloc(sizeof (int));
*p=6;
}
array[0] = *p;
free(p);
for (int i = 1; i < 5, i++)
array[i] += array[0];
return 0;
}
Memory is not allocated “to a pointer.”
A pointer is simply a variable that holds an address, the same way an int is a variable that holds an integer value (within a range).
Given some int x = 3;, when the program executes x = 8;, nothing is done with the 3 that is in x before the assignment except to overwrite it. It is gone, and there is a new value in x.
Similarly, when a new value is assigned to a pointer, nothing is done with its old value except to overwrite it. The old value is gone, and there is a new value in the pointer.
After int *p = malloc(sizeof *p);, p contains the address of the memory that malloc allocated, assuming it was successful.
This memory is not “allocated to the pointer.“ It is not bound in any way to the pointer. We could then do int *q = p; int *r = p; int *s = p;, and we would have four pointers all pointing to the same address, and they would be identical. None of them would have any particular claim on the memory.
Alternately, after int *p = malloc(sizeof *p);, we could do p = malloc(sizeof *p);, and this would store a new address in p. The old address is overwritten. The allocated memory is still allocated, because nothing freed it. But the program has lost track of its address.

Dynamically allocate struct of char array and int array

I am trying to use malloc to allocate memory for a struct containing a char array and an int array. I will be populating these two arrays with information from a file whose length I will not know in advance.
typedef struct bulk_data{
int *l_bulk_pos_arr;
char (*l_bulk_anc_arr)[10001];
}bulk_data;
I am still learning memory allocation, but what I imagine here is that since the size of each char array element is fixed, I shouldn't have to loop through that array to allocate memory. At this point I now know the number of array elements I need (n_rows). I have tried the following (obviously not all at the same time):
struct bulk_data *bulk_counts;
bulk_counts = malloc(sizeof(bulk_data)); // 1st attempt
bulk_counts = (bulk_data *)malloc(sizeof(bulk_data)); // 2nd
bulk_counts = malloc(sizeof(bulk_data) * n_rows); // 3rd
bulk_counts = (bulk_data *)malloc(sizeof(bulk_data) * n_rows); // 4th
No errors at compile time, but it appears that the above listed attempts aren't allocating the space properly:
(gdb) p bulk_counts->l_bulk_anc_arr
$1 = (char (*)[10001]) 0x0
(gdb) p bulk_counts->l_bulk_anc_arr[0]
Cannot access memory at address 0x0
(gdb) p bulk_data->l_bulk_pos_arr
$2 = (int *) 0x0
(gdb) p bulk_data->l_bulk_pos_arr[0]
Cannot access memory at address 0x0
I would like to know how I can allocate memory for this stated case, but also in the case when you don't know the number of chars in each char array element.
l_bulk_anc_arr is a pointer to an array of 10001 chars. It is not an array.
You still have to allocate memory for it.
struct bulk_data *bulk_counts;
bulk_counts = malloc(sizeof(bulk_data));
bulk_counts->l_bulk_pos_arr = malloc( /*some size*/ );
bulk_counts->l_bulk_anc_arr = malloc(10001);
Now, you can use:
(*bulk_counts->l_bulk_anc_arr)[0] = 'a';
(*bulk_counts->l_bulk_anc_arr)[1000] = '\0';
or
bulk_counts->l_bulk_anc_arr[0][0] = 'a';
bulk_counts->l_bulk_anc_arr[0][1000] = '\0';

Adding `int` to address causes int to be added 4 times

For a course about the functioning of operating systems, we had to write a malloc/free implementation for a specific sized struct. Our idea was to store the overhead, like the start and end of the specified (static) memory block our code has to work in, in the first few addresses of that block.
However, something went wrong with the calculation of the last memory slot; We're adding the size of all usable memory slots to the address of the first usable memory slot, to determine what the last slot is. However, when adding the int sizeofslots to the address of currentslot, it actually adds sizeofslots 4 times to this address. Here's the relevant code:
/* Example memory block*/
/* |------------------------------------------------------------------------------|*/
/* | ovr | 1 t | 0 | 1 t | 1 t | 1 t | 0 | 0 | 0 | 0 | 0 | 0 | 0 |*/
/* |------------------------------------------------------------------------------|*/
/* ovr: overhead, the variables `currentslot`, `firstslot` and `lastslot`.
* 1/0: Whether or not the slot is taken.
* t: the struct
*/
/* Store the pointer to the last allocated slot at the first address */
currentslot = get_MEM_BLOCK_START();
*currentslot = currentslot + 3*sizeof(void *);
/* The first usable memory slot after the overhead */
firstslot = currentslot + sizeof(void *);
*firstslot = currentslot + 3*sizeof(void *);
/* The total size of all the effective memory slots */
int sizeofslots = SLOT_SIZE * numslots;
/* The last usable slot in our memory block */
lastslot = currentslot + 2*sizeof(void*);
*lastslot = firstslot + sizeofslots;
printf("%p + %i = %p, became %p\n", previous, sizeofslots, previous + (SLOT_SIZE*numslots), *lastslot);
We figured it had something to do with integers being 4 bytes, but we still don't get what is happening here; Can anyone explain it?
C's pointer arithmetic always works like this; addition and subtraction is always in terms of the item being pointed at, not in bytes.
Compare it to array indexing: as you might know, the expression a[i] is equivalent to *(a + i), for any pointer a and integer i. Thus, it must be the case that the addition happens in terms of the size of each element of a.
To work around it, cast the structure pointer down to (char *) before the add.
When you add an integer to a pointer, it increments by that many strides (i.e. myPointer + x will increment by x*sizeof(x). If this didn't happen, it would be possible to have unaligned integers, which is many processor architectures is a fault and will cause some funky behaviour, to say the least.
Take the following as an example
char* foo = (char*)0x0; // Foo = 0
foo += 5; // foo = 5
short* bar = (short*)0x0; // Bar = 0; (we assume two byte shorts)
bar += 5; // Bar = 0xA (10)
int* foobar = (int*)0x0; // foobar = 0; (we assume four byte ints)
foobar += 2; // foobar = 8;
char (*myArr)[8]; // A pointer to an array of chars, 8 size
myArr += 2; // myArr = 0x10 (16). This is because sizeof(char[8]) = 8;
Example
const int MAX = 3;
int main ()
{
int var[] = {10, 100, 200};
int i, *ptr;
/* let us have array address in pointer */
ptr = var;
for ( i = 0; i < MAX; i++)
{
printf("Address of var[%d] = %x\n", i, ptr );
printf("Value of var[%d] = %d\n", i, *ptr );
/* move to the next location */
ptr++;
}
return 0;
}
Output::
Address of var[0] = bfb7fe3c
Value of var[0] = 10
Address of var[1] = bfb7fe40
Value of var[1] = 100
Address of var[2] = bfb7fe44
Value of var[2] = 200
You can deduce from the example that, a pointer increments itself by "Number Of Bytes" = "Size of the type it is pointing to". Here it is, Number Of bytes = sizeof(int). Similarly, it will increment itself 1 byte in case of char.

How to initialize the structure member with using pointer?

I have below code. In below code the value 5 gets stored in variable a(i.e abc.a). But I would like to intialize the value in c (i.e abc.c). How to do that? My requirement is to fill the data for c not for a.
typedef struct abc
{
int a;
int b;
int c;
}abc;
typedef struct def{
int *ptr;
abc strpt;
}def;
typedef struct xyz{
int *pointer;
}xyz;
int main()
{
int *temp, tmp;
abc* ab;
tmp = 5;
temp = &tmp;
ab = (abc*)malloc(sizeof(abc));
xyz *x = (xyz*)malloc(sizeof(xyz));
def *de = (def*)malloc(sizeof(def));
x->pointer = (xyz*)temp;
ab = (abc*)x->pointer;
return 0;
}
Please help me.
I'm Affraid some serious lack of understanding pointers manifests in your code. Let me dissect it line by line to make clear where problems occur.
I numbered the statements in order to make easy references, assuming the type declarations as above.
int main()
{
int *temp, tmp;
abc* ab;
/* 1 */ tmp = 5;
/* 2 */ temp = &tmp;
/* 3 */ ab = (abc*)malloc(sizeof(abc));
/* 4 */ xyz *x = (xyz*)malloc(sizeof(xyz));
/* 5 */ def *de = (def*)malloc(sizeof(def));
/* 6 */ x = (xyz*)temp;
/* 7 */ ab = (abc*)x;
return 0;
}
First of all: You never clean up the memory allocated in 3, 4 and 5. Even for a simple test program, you should always take care of stuff like this.
Your first problem is line 6 where you blindly cast a pointer to an object of type int (4 bytes in memory) into a pointer to a structure of type xyz (4 or 8 bytes in memory, different type). What you do here is a complicated way to write x = (xyz*)&tmp;.
An action like that leads to following serious problems:
You just allocated memory in line 4. Now you overwrite this pointer with a pointer to your stack variable. Therefore you can't free the allocated memory anymore ==> Memory leak
Your newly assigned pointer to the stack variable becomes invalid after exiting the scope and can cause undefined behaviour.
Any write attempt to elements of x after line 6 can lead to corruption of the stack (and therefore undefined behaivour) due to a possible size mismatch of elements.
By line 7 you get the same problems again and even worse. The estimated sizeof(abc) is possibly 12 bytes. Accessing any element of abc after this line can lead to stack corruption again.
I still don't understand what you really are looking for but if you "have to" initialize a structure element through pointers there are a several ways:
If the struct ist known you can do it like this:
abc * ab = malloc(sizeof(abc));
if (ab != NULL) {
ab->c = 5;
// -- do other stuff
free(ab); ab = NULL;
}
If you need a pointer to the element 'c' you can do it like this:
int * c_ptr = NULL;
abc * ab = malloc(sizeof(abc));
if (ab != NULL) {
c_ptr = &(ab->c);
*c_ptr = 5;
//-- do other stuff
free(ab); ab = NULL;
}
Are you asking for this:
abc s;
s.c = 5;
That makes c 5. Or you could do thos:
abc s = {0,0,5};
That means, the first two members are initialized to 0, and third one (which is c) is initialized to 5.
Or if you've pointer, then you can do this:
abc *p = malloc(etc);
p->c = 5;
But then avoid using pointers and malloc. Use it when you really need them. In your code, I don't see any reason why you would need it. Use automatic variables, not pointers.
I think you would need to add this before return in your main() to get what you need.
ab->c = *(x->pointer);

Resizing a char* on the fly - why does this code *work*? [duplicate]

This question already has answers here:
No out of bounds error
(7 answers)
Closed 7 years ago.
I'm experimenting with malloc & realloc and came up with some code for the following problem:
I want to create a string of unknown size, without setting any limit. I could ask
the user for a nr of chars, but I rather resize the str as the user
types each character.
So I was trying to do this with malloc + realloc and the idea was that everytime the user enters a new char, I use realloc to request +1 piece of memory to hold the char.
While trying to implement this, I did a mistake and ended up doing the following:
int main () {
/* this simulates the source of the chars... */
/* in reality I would do getch or getchar in the while loop below... */
char source[10];
int i, j;
for (i=0, j=65; i<10; i++, j++) {
source[i] = j;
}
/* relevant code starts here */
char *str = malloc(2 * sizeof(char)); /* space for 1 char + '\0' */
int current_size = 1;
i = 0;
while(i<10) {
char temp = source[i];
str[current_size-1] = temp;
str[current_size] = '\0';
current_size++;
printf("new str = '%s' | len = %d\n", str, strlen(str));
i++;
}
printf("\nstr final = %s\n", str);
return 0;
}
Note that the realloc part is not implemented yet.
I compiled and executed this code and got the following output
new str = 'A' | len = 1
new str = 'AB' | len = 2
new str = 'ABC' | len = 3
new str = 'ABCD' | len = 4
new str = 'ABCDE' | len = 5
new str = 'ABCDEF' | len = 6
new str = 'ABCDEFG' | len = 7
new str = 'ABCDEFGH' | len = 8
new str = 'ABCDEFGHI' | len = 9
new str = 'ABCDEFGHIJ' | len = 10
I found these results weird, because I expected the program to crash: str has space for 2 chars, and the code is adding more than 2 chars to the str without requesting more memory. From my understanding, this means that I'm writing in memory which I don't own, so it should give a runtime error.
So... Why does this work?
(The compiler is GCC 4.3.4.)
Thanks in advance.
EDIT:
One of the commenters suggesting that a call to free() could lead to the error being signaled. I tried calling free() with the above code and no error resulted from executing the code. However, after adding more items to the source array, and also calling free, the following error was obtained:
* glibc detected ./prog: free(): invalid next size (fast): 0x09d67008 **
Since you're writing past the allocated memory, your code has undefined behaviour.
The fact that the code happened to not crash once (or even many times) does not change that.
Undefined behaviour doesn't mean that the code has to crash. In your case, there happens to be some memory immediately following str, which you're overwriting. The actual effects of overwriting that memory are not known (you could be changing the value of some other variable, corrupting the heap, launching a nuclear strike etc).
seems from glibc-2.14, memory allocate will allocate as the size as follows, and it will set border, so when you allocate 2 byte size " char *str = malloc(2 * sizeof(char))", it seems memory allocated is no less than 16 byte, so you may add more items and then cause the programe error.
struct _bucket_dir bucket_dir[] = {
{ 16, (struct bucket_desc *) 0},
{ 32, (struct bucket_desc *) 0},
{ 64, (struct bucket_desc *) 0},
{ 128, (struct bucket_desc *) 0},
{ 256, (struct bucket_desc *) 0},
{ 512, (struct bucket_desc *) 0},
{ 1024, (struct bucket_desc *) 0},
{ 2048, (struct bucket_desc *) 0},
{ 4096, (struct bucket_desc *) 0},
{ 0, (struct bucket_desc *) 0}}; /* End of list marker */
void *malloc(unsigned int len)
{
struct _bucket_dir *bdir;
struct bucket_desc *bdesc;
void *retval;
/*
* First we search the bucket_dir to find the right bucket change
* for this request.
*/
for (bdir = bucket_dir; bdir->size; bdir++)
if (bdir->size >= len)
break;
if (!bdir->size) {
printk("malloc called with impossibly large argument (%d)\n",
len);
panic("malloc: bad arg");
}
/*
* Now we search for a bucket descriptor which has free space
*/
cli(); /* Avoid race conditions */
for (bdesc = bdir->chain; bdesc; bdesc = bdesc->next)
if (bdesc->freeptr)
break;
/*
* If we didn't find a bucket with free space, then we'll
* allocate a new one.
*/
if (!bdesc) {
char *cp;
int i;
if (!free_bucket_desc)
init_bucket_desc();
bdesc = free_bucket_desc;
free_bucket_desc = bdesc->next;
bdesc->refcnt = 0;
bdesc->bucket_size = bdir->size;
bdesc->page = bdesc->freeptr = (void *) cp = get_free_page();
if (!cp)
panic("Out of memory in kernel malloc()");
/* Set up the chain of free objects */
for (i=PAGE_SIZE/bdir->size; i > 1; i--) {
*((char **) cp) = cp + bdir->size;
cp += bdir->size;
}
*((char **) cp) = 0;
bdesc->next = bdir->chain; /* OK, link it in! */
bdir->chain = bdesc;
}
retval = (void *) bdesc->freeptr;
bdesc->freeptr = *((void **) retval);
bdesc->refcnt++;
sti(); /* OK, we're safe again */
return(retval);
}
Besides the fact that you're triggering undefined behaviour, which includes but does not mandate "crash", I think your application actually does own the memory you're writing to.
On modern operating systems memory is handled in pages, chunks of memory way larger than two bytes. AFAIK malloc asks the OS for full pages and divides them internally if needed. (Note: implementation dependent, but I think at least glibc operates this way.) So the OS lets you write to the memory, because it's technically yours. Internally, malloc generally divides the page and supplies parts of it at each request. So you might overwrite another variable on your heap. Or write beyond the bounds to, according to malloc's view, memory still waiting to be requested.
I expect a crash only when you try to write to a page that hasn't been allocated from the OS yet or is marked as read only.
[Putting the fact that the behavior is undefined for such operation]
The integrity of the heap is often checked when calling realloc or free, and not at each write, you probably didn't override enough to get a crash.
Note that you didn't call free at the end, if you would, you'll probably get the crash.
To add to the previous answer, really does not have space for 2, it's just a pointer in the memory. Somewhere, malloc remembers that it gave out space for 2 characters but that's malloc's internal working.
You can try the following little experiment to see how this works:
Create another pointer just behind the first one.
char *str2 = str + 5;
/* or you could simply malloc another */
char *str2 = malloc(2);
printf("str=%d, str2=%d\n",str,str2);
/* to eyeball the pointers actually received
and note the difference in the two pointers.
You will need to raise source length to at least
that much to see the results below
*/
and introduce another printf in the loop after the first one:
printf("new str2 = '%s' | len = %d\n", str2, strlen(str2));
Sooner or later str2 will also begin to show the same letters.
HTH

Resources