以下代码在没有语句d = *dummy;
的情况下工作正常,该语句是双指针取消引用。但是,如果存在此线,则会发生分段错误。为什么会这样?
该代码动态分配和初始化数据结构的内存。我试图简化对返回的指针到指针的访问。
#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: %dn", (*dummies + i)->dummy_number);
}
}
提前谢谢。
由于UB而出错,部分原因是尝试使用没有内存的可变对象。dummies
虽然是作为Dummies **
创建的,但从未被提供过记忆。 至少,编译器应该警告您在此调用中未初始化dummies
:
err = load_dummies(dummies, p_num_of_dummies);
只需在创建变量时初始化变量即可轻松解决此问题:
Dummy** dummies = {0}; //this initialization eliminates compile time warnings
^^^^^
然后是运行时错误。 第一个在我的系统上称为致命运行时,这意味着操作系统由于严重问题而拒绝继续,在这种情况下,尝试取消引用此行中的空指针:
假人 = (假人) calloc(*num_of_dummies, sizeof(假人));
因为您创建了一个名为dummies
的Dummy **
,所以第一步是为指向指针dummies
的指针创建内存,然后为将产生的多个dummies[i]
实例创建内存。 只有这样,才能写信给他们中的任何一个成员。
这里有一种方法说明了如何为指向指针(d
)和多个Dummies
实例(d[i]
)的Dummies
指针创建内存:
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;
}
在你的主函数中,顺便说一下,它应该至少原型化为:int main(void){...}
,这个版本的loadDummies可以这样调用:
...
Dummies **dummies = loadDummies(4, 80);
if(!dummies) return -1;//ensure allocation of memory worked before using `dummies`.
...
使用此dummies
集合后,请确保以相反的创建顺序释放所有集合。 首先释放dummies[0]-dummies[numPointers-1]
的所有实例,然后释放指向指针的指针,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);
}
这样称呼:
freeDummies(dummies, 4);
dummies
从未被分配过值,因此取消引用将尝试访问一些随机内存,这几乎肯定不会成为程序分配内存的一部分。您应该已将其分配给 &d。
但你甚至不需要这样做。只需在调用函数时&d
使用一次即可。
此外,如果返回分配的假人数而不是 1/0,则可以简化代码。如下所示(未测试):
#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: %dn", d[i].dummy_number);
}
}
if(d) { // clean up
free(d);
}
return 0;
}