I need to make an array of structs dynamically and I don't know the size when executing the malloc command. So I thought I could use realloc every time I need another struct! For example this code:
main:
int main(void) {
flights *flight_list = NULL;
int numFlights = 0;
numFlights = load_flights(&flight_list);
/* output flights. Problem: Only first flight is there, the second is not allocated! */
Here's the function:
short load_flights(flights **flight_list) {
flight_list[0] = calloc(1, sizeof(flights));
flight_list[0]->price = 69;
flight_list[0] = realloc(*flight_list, sizeof(flights)*2);
flight_list[1]->price = 70;
return 2; //num of flights-structs
The problem is, that actually 2 elements should be created, but only 1 element is there - check this debugging screenshot:
As you can see, flight_list[0] is there, but flight_list[1] not! But realloc should do the job?
Am I understanding anything wrong?
There's a bug in this line:
flight_list[1]->price = 70;
Both [] and -> dereference pointers. a[b] is equivalent to *(a+b) and a->b is equivalent to (*a).b. Your line therefore means:
(**(flight_list + 1)).price = 70;
However, flight_list (in load_flights) is a pointer to the flight_list variable in main! In the context of main, you're computing &flight_list + 1, which is an invalid pointer: You're getting the contents of memory that happens to be next to a local variable.
The correct code would be:
(*(*flight_list + 1)).price = 70;
*flight_list is the pointer returned by realloc. Here we can step one element ahead in the dynamic array.
We can also write this as:
(*flight_list)[1].price = 70;
Your flight_list is an array of pointers to pointers of flights.
With flight_list[0] = realloc(*flight_list, sizeof(flights)*2); you allocate space for two flights to the item flight_list[0], but flight_list itself remains unchanged. In fact, there is no code that allocates any space for flight_list at all, but maybe you just left out this code in your example.
If the realloc line of code is what you wanted, you should watch these memory locations in the debugger: flight_list[0][0] for the first flight, and flight_list[0][1] for the second.
Related
I have to dynamically increase a length of double array. I know, how to do it with char array, so I tried this:
int main() {
char * tmp = NULL;
for (int i = 1; i <= 4; i++) {
tmp = realloc(tmp, i * sizeof(char));
tmp[i] = 'i';
}
puts("char OK");
double * tmp1 = NULL;
for (int i = 1; i <= 4; i++) {
tmp1 = realloc(tmp1, i * sizeof(double));
tmp1[i] = 0;
}
return 0;
}
The first array works fine. But the second one crushes with message realloc(): invalid next size.
These are my 2 questions:
Why this way doesn't work in a double array?
How to dynamically increase the size of array of doubles?
UPD:
removed a typo
TL;DR: Both the snippets are wrong, the first one appears to work because of undefined behavior.
To elaborate, the problem is with your indexing logic. C uses a 0-based indexing. So, inside the loop which is staring the iteration from value of i as 1, by using
tmp[i] = .......
you're trying to access invalid memory, at this point, only access up to tmp[i-1] is valid.
You need to use tmp1[i-1] = 0;, and likewise.
That said,
Always check for the success of the memory allocator functions before using the returned pointers.
Never use the form
pointer = realloc (pointer, ......)
because, in case realloc call fails, you'll end up losing the original pointer, too.
Quoting C11, chapter §7.22.3.5
The realloc function returns a pointer to the new object (which may have the same
value as a pointer to the old object), or a null pointer if the new object could not be
allocated.
and
[....] If memory for the new object cannot be
allocated, the old object is not deallocated and its value is unchanged.
Always use a temporary pointer variable to store the return value of realloc(),
check for the success of the call [not-null return value] and
then assign it back to the original variable, if needed.
I'm currently trying to do something simple, turn my list of nodes into an array of pointers to the nodes, so that I could use it for another functionality.
typedef struct {
int data;
} myNode;
In the function where I'm trying to make my array of node pointers, I write something like (assume I have a list called myList of all the nodes):
myNode** aryPtr = malloc(sizeof(myNode*)) * numItemsInList);
and for each spot, I allocate memory for the pointer doing:
int inc = 0;
int z = 0;
aryPtr[inc] = malloc(sizeof(myNode));
aryPtr[inc] = &(myList[z]);
inc += 1;
z += 1;
I've been trying to do something like this to go about storing the pointers to each of my nodes in an array, but haven't had success and don't entirely understand how to make an array of pointers (using a double pointer). Any help on how to store pointers into a dynamically allocated array of pointers would help a lot.
These two lines are a little problematic:
aryPtr[inc] = malloc(sizeof(myNode));
aryPtr[inc] = &(myList[z]);
The first assignment
aryPtr[inc] = malloc(sizeof(myNode));
allocates memory, and makes aryPtr[inc] point to that memory. But the next assignment
aryPtr[inc] = &(myList[z]);
throws away the result of the malloc call, and reassigns aryPtr[inc] to point somewhere else. That leads to a memory leak.
It's similar to having a simple int variable, and assigning it multiple times:
int a;
a = 5;
a = 10;
And then wonder why a is not equal to 5.
To solve this problem, either drop the first assignment with the malloc and only have
aryPtr[inc] = &myList[z]; // Make aryPtr[inc] point to myList[z]
Or dereference the destination pointer to copy the structure:
aryPtr[inc] = malloc(sizeof(myNode));
*aryPtr[inc] = myList[z]; // Copy the structure itself
Another couple of things:
With the code you show (you really need to provide a proper Minimal, Complete, and Verifiable Example) it looks like you're always using index 0 for both aryPtr and myList. You also use the same index for both aryPtr and myList, so you only need a single variable for that.
As a part of our Computer Science course (using C), we are to build a VERY wasteful system using pointers
Since we are not allowed to use structures at this point, we are to use ONLY pointers for our dynamic-arrays.
I have created the dynamic-array **students and allocated space for it.
at this point, i send this dynamic array (**students) to a function that sends it to ANOTHER function (i send &students so i can change them by address)
My problem is, that i do not know (apparently - and after many many tries) how to reallocate space to this dynamic-array
To be specific, since i sent the array 2 times:
my first function receives ***students
and my second function receives ****students
I tried to reallocate space the following way (I am in the SECOND function at the moment)
*students = (char**)realloc(*students, 2 * sizeof(char*));
*students[1] = (char*)malloc(sizeof(char))
this seemed like the way to do it - apparently i was wrong
any help would be thankfully received :)
Edit:
The program will run if I do this:
**students = (char**)realloc(**students, 2 * sizeof(char*));
but then I am not able to use malloc correctly..
I would appreciate the understanding behind my question and not just a solution, so I can learn for next trial.
I have created the dynamic-array **students and allocated space for
it. at this point, i send this dynamic array (**students) to a
function that sends it to ANOTHER function (i send &students so i can
change them by address)
…
To be specific, since i sent the array 2 times: my first function
receives ***students and my second function receives ****students
There is no sense in taking the array pointer's address (i. e. &students) more than once, since we then already have the means to reallocate the array:
void ANOTHER_function(char ***students)
{
*students = realloc(*students, 2 * sizeof **students); // room for 2 char *
(*students)[1] = malloc(sizeof *(*students)[1]); // room for 1 char
}
void a_function(char ***students)
{
ANOTHER_function(students); // no need for address operator & here
}
int main()
{
char **students = malloc(sizeof *students); // room for 1 char *
students[0] = malloc(sizeof *students[0]); // room for 1 char
a_function(&students);
}
So, we don't need more than three * anywhere here.
When you had ANOTHER_function(char ****students) and therein
*students = (char**)realloc(*students, 2 * sizeof(char*));
the type of *students was char *** and didn't match the (char**) on the right - fortunately, because *students was the address of main's students instead of its value.
**students = (char**)realloc(**students, 2 * sizeof(char*));
was correct (albeit overly complicated) in this case; the corresponding malloc() for the new element would have been
(**students)[1] = malloc(sizeof *(**students)[1]);
I asked this before, but no one answered so revise my questions. I have tried to analyze this codes but it doesn't make sense for me. This time hopefully someone give me an idea or correct my misunderstanding.
char * p pointing to command array is type-casted to CMD_BLOCK * after getting thru a couple of functions.
extern CHGR_CMD command[96]
+---+---+---+---+
(CMD_BLOCK *(char *p)) -> | CHGR_CMD | command[0]
+---+---+---+---+
| CHGR_CMD | command[1]
+---+---+---+---+ ....
| .... | command[95]
+---+---+---+---+
Here is a struct of CMD_BLOCK and union CHGR_CMD
typedef struct cmd_block {
struct cmd_block *next;
short type;
short unused;
CHGR_CMD c; //Union
} CMD_BLOCK;
typedef union chgr_cmd {
NET_HDR n; //struct
CHGR_SC_SETUP su;//struct
CHGR_SC_START st;//struct
CHGR_SC_STOP sp;//struct
....
} CHGR_CMD;
the below variables are used in cmd_init()
#define CMD_OFFSET (sizeof(struct cmd_block *) + 2*sizeof(short))
block_size = sizeOf(CHGR_CMD)
size = 96*sizeOf(CHGR_CMD)
Especially, I don't get the for loop below:
int cmd_init(register char* p, register long size, int block_size)
{
int i;
if((size <= 0) || (block_size <= 0) || (block_size > size))
return(-1);
cmd_out_head = NULL;//extern var
cmd_out_tail = NULL;//extern var
cmd_free_space = NULL;//extern var
block_size += CMD_OFFSET;// turn to be size of CMD_BLOCK
cmd_blocks_free = 0;
cmd_blocks_used = 0;
for(i=0; size >= block_size; size-=block_size, i++, p+=block_size) {
((CMD_BLOCK *)(p))->next = cmd_free_space;
cmd_free_space = (CMD_BLOCK *)(p);
cmd_blocks_free++;
}
cmd_b = NULL;
status_seq_clear();
return(i);
}
for loop iterates until 96 which is size of command array.
p+=block_size keeps adding size of CMD_BLOCK ---> I don't get how this works?. Initially type of array was CHGR_CMD and type-casting to char * then another casting to CMD_BLOCK * then increasing the size of CMD_BLOCKin for-loop??
I am not sure but assumed that type of command array is now turning to be CMD_BLOCK after a couple of type-casting.
Another thing I don't get is this codes:
((CMD_BLOCK *)(p))->next = cmd_free_space;
cmd_free_space = (CMD_BLOCK *)(p);
It doesn't seem like linking together. cmd_free_space seems to point the last element of the array while * p gets increased by the size of CMD_BLOCK.
Regarding the cast from char* to CMD_BLOCK*, It is hard to tell without looking at more code, but most probably the original programmer wanted to give some opacity to the p parameter, that is, maybe he/she didn't want to expose the fact that the function is receiving an array of CMD_BLOCK structs.
This opacity is sometimes exercised on certain APIs to try to minimize the chance that a data structure is directly manipulated by the programmer, bypassing the tested API.
See here for more details on opaque pointers.
In order to remove the opacity, a programmer needs to explicitly cast the opaque pointer to the concrete type that is actually being passed. This is what seems that is being done with the line ((CMD_BLOCK *)(p))->next = cmd_free_space;
As to what the for block is doing, it is actually building a reversed linked list from an array of contiguous CMD_BLOCK structures. The first node's next pointer is initialized to NULL, becoming the tail of the linked list, the second node's next pointer is pointed to the first node and so forth, until the last block becomes the head of the list and seems to be accessible through the cmd_free_space variable as you point out.
** EDIT **
To better illustrate how the list is built, I'll try to step through the first two iterations.
iteration 1
State at the beginning of the iteration:
cmd_free_space is NULL;
p is pointing to the first element of the array.
Execution:
p->next = cmd_free_space; p->next becomes NULL;
cmd_free_space = p; cmd_free_space is pointing to the first element of the array
p += block_size; p is now pointing to the second element of the array
iteration 2
State at the beginning of the iteration:
cmd_free_space is pointing to the first element of the array
p is pointing to the second element of the array.
Execution:
p->next = cmd_free_space; p->next = first element of the array (link is done)
cmd_free_space = p; cmd_free_space is now pointing to the second element of the array
p += block_size; p is now pointing to the third element of the array
and so on...
** END OF EDIT **
I would remove from the for block the i variable, as it is useless (it is neither controlling the number of iterations nor indexing anything).
** EDIT: **
I hadn't noticed that the ´i´ variable is returned from the function, so it most probably has a purpose, outside of the function. The function is actually returning the number of elements that were actually processed in the for loop.
** END OF EDIT **
The fact that blocksize is a variable parameter and not simply sizeof(CMD_BLOCK) may also indicate that the function can initialize a linked list with an array of structs that contain as first member a CMD_BLOCK struct, but that also carry additional data. By adding blocksize to the pointer that is walking the array, the for loop would effectively skip over the extra data.
This initialization of an array into a linked list may seem a strange thing to do, but I would guess that the programmer needed the flexibility of inserting commands in the middle of the list without having to copy/move elements in the original array to make space.
I have been debugging a piece of legacy code, running on an XScale (arm v5te) System with linux, that crashes reproducible.
I have debugged using gdb and set MALLOC_CHECK_ to 1. It's a lot of code, so just some snippets:
We have this structure:
typedef struct {
...clipped..
char **data_column_list;
/** data column count */
int data_column_cnt;
...clipped
} csv_t;
We initialize the columns in a function, putting them in a variable "columns"
/* Allocating memory for pointer to every register id */
columns = (char **) malloc(column_cnt * sizeof(char *));
column_cnt = 0;
/* loop over all sensors */
for(i=0; i<cfg.sen_cnt; i++) {
/* loop over all registers */
for(j=0; j<cfg.sen_list[i]->data_cnt; j++) {
/* Storing all the pointers to id */
columns[column_cnt++] = cfg.sen_list[i]->data_list[j]->id;
}
}
In another function, what happens is this:
/* free the previous list */
csv_free(lc_csv);
lc_csv->data_column_list = columns;
lc_csv->data_column_cnt = column_cnt;
csv_free being:
void csv_free(csv_t *csv) {
if(csv->data_column_cnt > 0)
free(csv->data_column_list);
csv->data_column_cnt = 0;
}
Now, there is another function, building the whole "cfg"/config structure, that contains these ids.
Code frome above: cfg.sen_list[i]->data_list[j]->id; where cfg is a struct, sen_list is an array of pointers to structs, data_list is an array of pointers to other structs, that contain a string "id".
Whe the program gets a signal SIGUSR1, the config is being updated. All of these data_list and sen_list structs are being freed, then new ones are generated.
Then with the first function, new collumns of ids are generated and put into the csv structure, but the old list is being freed before.
Thats where it crashes. In csv_free.
*** glibc detected *** /root/elv: free(): invalid pointer: 0x0001ae88 ***
I thought it should be like this. You have an array of pointers. When you free the pointers, you have to free the pointer, pointing to a set of pointers (the array).
Or put in code terms, the above situation should be analog to:
char **ar = malloc(n * sizeof(char *));
char *xn = malloc(10 * sizeof(char)); // Do for 0 to n strings
...
ar[n] = xn; // Do for 0 to n strings
...do stuff...
free(xn); // Do for 0 to n strings
free(ar);
When the structs, containing the id strings, are freed, I still have my pointer arrays with (invalid) pointers, not null pointers:
(gdb) p csv
$40 = {sysid = 222, ip = '\0' <repeats 49 times>,
module = "elv_v2", '\0' <repeats 14 times>, format_type = 1, msg_id = 0,
data_column_list = 0x1ae88, data_column_cnt = 10, pub_int = 30,
line_cnt = 0, pub_seq = -1, format = 0x18260}
(gdb) p csv.data_column_list[0]
$41 = 0x1b378 "0"
But I get the above error message (or SIGABRT without the MALLOC_CHECK_).
I don't understand this at all. I have to free this array of pointers, or it will become a memory leak. There is no other call of free before that, that I could find. I don't know why csv.data_column_list is considered an invalid pointer.
Valgrind is unfortunately not availiable on arm v5te :(
Have been debugging this for hours and hours and would be happy for any help.
Thank you very much,
Cheers,
Ben
UPDATE:
I'm wondering if it could be connected to some "scope" issue. There is almost identical code in another application, which works. The function which crashes, "csv_free" is used by both programs (statically linked). The only difference is, that the struct containing the pointer to be freed is declared and defined normally in the working program and declared as external and defined in another file than main.c
Calling "free" manually in main.c works, while calling "csv_free" crashes. Riddle me this...
9 out of 10 times when I run into free() errors the problem actually started in the allocation or initialization, so let's verify that a bit:
Where do you actually assign columns to csv.data_columns_list before you call csv_free? If it's uninitialized when you free(), that would explain the error.
In the second code block, if the initial column_cnt (which I guess is set
elsewhere?) is less than the column_cnt after the loop you would be writing outside the
array. One would hope MALLOC_CHECK_ would catch that, but what happens if you assert as
follows:
/* Allocating memory for pointer to every register id */
columns = (char **) malloc(column_cnt * sizeof(char *));
int old_column_cnt = column_cnt;
column_cnt = 0;
/* loop over all sensors */
for(i=0; i<cfg.sen_cnt; i++) {
/* loop over all registers */
for(j=0; j<cfg.sen_list[i]->data_cnt; j++) {
/* Storing all the pointers to id */
columns[column_cnt++] = cfg.sen_list[i]->data_list[j]->id;
}
}
assert(old_column_cnt >= column_cnt);
Looking over my old questions I saw this. I can't really verify, since I don't work at that company anymore, but thinking of other issues we had, I think wildplasser was right.
Calling any large functions from within signal handlers is a bad idea. Especially if you haven't check whether everything you do is reentrant. It was legacy code, so at least it's not completely my fault ;)
Nowadays I would set a flag in the signal handler and call the routine in my main loop, when that flag is set (or something like that).