The following code works fine without the statement d = *dummy;
which is a double pointer dereference. However if this line is present, a segmentation fault occurs. Why so?
The code allocates and initializes memory for data structs dynamically. I was trying to simplify access to the returned pointer-to-pointer.
#include <stdlib.h>
#include <stdio.h>
typedef struct s_dummy {
char dummy_number;
} Dummy;
int mock_read_from_external_source() {
return 4;
}
int load_dummies(Dummy** dummies, int* num_of_dummies) {
*num_of_dummies = mock_read_from_external_source();
*dummies = (Dummy*) calloc(*num_of_dummies, sizeof(Dummy));
if (!dummies) {
return 1; // allocation unsuccessful
}
// Iterate dummies and assign their values...
for (int i = 0; i < *num_of_dummies; i++) {
(*dummies + i)->dummy_number = i;
}
return 0;
}
void main() {
Dummy** dummies;
Dummy* d;
int num_of_dummies = 0;
int *p_num_of_dummies = &num_of_dummies;
int err;
err = load_dummies(dummies, p_num_of_dummies);
// Segmentation fault occurs when dummies is dereferenced
d = *dummies;
if (err) {
exit(err);
}
for (int i = 0; i < num_of_dummies; i++) {
printf("Dummy number: %d\n", (*dummies + i)->dummy_number);
}
}
Thanks in advance.
You are getting the fault because of UB , in part caused by trying to use variable objects without memory. dummies
, although created as a Dummies **
, has never been provided memory. At the very least, your compiler should have warned you about dummies
not being initialized in this call:
err = load_dummies(dummies, p_num_of_dummies);
This is easily addressed by simply initializing the variable when it is created:
Dummy** dummies = {0}; //this initialization eliminates compile time warnings
^^^^^
Then come the run-time errors. The first is called a fatal run-time on my system, which means the OS refused to continue because of a serious problem, in this case an attempt to dereference a null pointer in this line:
dummies = (Dummy ) calloc(*num_of_dummies, sizeof(Dummy));
Because you created a Dummy **
called dummies
, the first step is to create memory for the pointer to pointers dummies
, then create memory for the several instances of dummies[i]
that will result. Only then can the members of any of them be written to.
Here is one method illustrating how memory can be created for a Dummies
pointer to pointers, ( d
) and several Dummies
instances ( d[i]
):
Dummy ** loadDummies(int numPointers, int numDummiesPerPointer)
{
int i;
Dummy **d = {0};
d = malloc(numPointers * sizeof(Dummy *));//Create Dummies **
if(!d) return NULL;
for(i=0;i<numPointers;i++)
{ //Now create Dummies *
d[i] = malloc(numDummiesPerPointer*sizeof(Dummy)); //random size for illustration
if(!d[i]) return NULL;
}
return d;
}
In your main function, which by the way should really be prototyped at a minimum as: int main(void){...}
, this version of loadDummies could be called like this:
...
Dummies **dummies = loadDummies(4, 80);
if(!dummies) return -1;//ensure allocation of memory worked before using `dummies`.
...
After using this collection of dummies
, be sure to free all of them in the reverse order they were created. Free all instances of dummies[0]-dummies[numPointers-1]
first, then free the pointer to pointers, dummies
void freeDummies(Dummy **d, int numPointers)
{
int i;
for(i=0;i<numPointers;i++)
{
if(d[i]) free(d[i]);
}
if(d) free(d);
}
Called like this:
freeDummies(dummies, 4);
dummies
was never assigned a value, so de-referencing will attempt to reach some random memory which is almost certainly not going to be part of your program's allocated memory. You should have assigned it to &d.
But you don't even need to do that. Just use &d
once when you call the function.
Also, if you return the number of dummies allocated instead of 1/0, you can simplify your code. Something like the below (not tested):
#include <stdio.h>
int mock_read_from_external_source() {
return 10;
}
typedef struct Dummy {
int dummy_number;
} Dummy;
int load_dummies(Dummy** dummies) {
int want, i = 0;
if((want = mock_read_from_external_source()) > 0) {
*dummies = (Dummy*) calloc(want, sizeof(Dummy));
if(*dummies) {
// Iterate dummies and assign their values...
for (i = 0; i < want; i++) {
(*dummies)[i].dummy_number = i;
}
}
}
return i;
}
int main() {
Dummy* d = NULL;
int num_of_dummies = load_dummies(&d); // when &d is de-referenced, changes are reflected in d
if(num_of_dummies > 0) {
for (int i = 0; i < num_of_dummies; i++) {
printf("Dummy number: %d\n", d[i].dummy_number);
}
}
if(d) { // clean up
free(d);
}
return 0;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.