函数中的结构数组 realloc - 产生未定义的行为
Struct array realloc in function - produces undefined behaviour
我有一个包含 3 个字符指针(任意长度字符串)的结构,我用 malloc 创建了一个动态数组,因为它可以有任意数量的条目。
这是我的结构数据类型:
typedef struct student{
char* name;
char* phoneNumber;
char* department;
}STUDENT;
我使用一个函数重新分配以在需要新条目时增加结构数组的大小,并使用另一个函数打印整个数组。
我遇到的问题是:
我能够在 addNumber 函数内打印新条目,但当我尝试在 addNumber 函数外打印时,情况并非总是如此。有时它有效,大多数时候我遇到分段错误:11 并且有一次在添加新条目时我收到“malloc:对象 0x7fc426c058f0 的 *** 错误:未分配正在重新分配的指针”
这是我的主要内容:
int nEntry = 0;
STUDENT* directory = malloc(nEntry * sizeof *directory);
if(directory == NULL){
puts("Unable to allocate memory");
exit(-1);
}
while(1){
int choice = 0;
scanf("%d", &choice);
while(getchar() != '\n');
switch(choice){
case 1:
printDirectory(directory, nEntry);
break;
case 2:
addNumber(directory, &nEntry);
break;
default:
printf("Unknown option!\n");
break;
}
}
return 0;
这是我的 addNumber 函数:
void addNumber(STUDENT* Array, int* nArray){
*nArray += 1;
int x = *nArray - 1;
STUDENT* tempDirectory = realloc(Array, *nArray * sizeof *Array);
if(tempDirectory == NULL){
puts("Unable to allocate memory");
exit(-1);
}
else{
Array = tempDirectory;
Array[x].name = (char*)malloc(sizeof(char*));
Array[x].phoneNumber = (char*)malloc(sizeof(char*));
Array[x].department = (char*)malloc(sizeof(char*));
printf("Name: ");
scanf("%[^\n]", Array[x].name);
while(getchar() != '\n');
printf("Number: ");
scanf("%[^\n]", Array[x].phoneNumber);
while(getchar() != '\n');
printf("Department: ");
scanf("%[^\n]", Array[x].department);
while(getchar() != '\n');
for(int i = 0; i < *nArray; i++){
printf("%s\t%s\t(%s)\n", (Array + i)->name, (Array + i)->phoneNumber, (Array + i)->department);
}
}
}
这是我的打印功能:
void printDirectory(STUDENT* Array, int nArray){
int i;
for(i = 0; i < nArray; i++){
printf("%s\t%s\t(%s)\n", (Array + i)->name, (Array + i)->phoneNumber, (Array + i)->department);
}
}
如果我将条目硬编码到 main 中,打印函数工作正常,问题似乎是在 addNumber 函数中创建的内容没有正确传回?但是对于我通过引用传递的所有参数,我很困惑为什么我会得到一个未定义的行为。
正如评论中指出的那样,您的 malloc
大小不正确,因此您的代码还有其他问题,但要解决您对 realloc 的具体问题:
要存储 realloc
的 return 值以便可以在主函数中访问它,您需要传递指针的地址。
所以主要是:
addNumber(&directory, &nEntry); // Note the ampersand
并在 addNumber 中:
void addNumber(STUDENT** Array, int* nArray){ // Note the pointer to a pointer
...
STUDENT* tempDirectory = realloc(*Array, *nArray * sizeof *Array); // Note Array is dereferenced
...
*Array = tempDirectory;
...
如果您将 main 中的 directory
描绘为存储在位置 0x1 并指向内存位置 0x2 的变量,则在您当前的代码中,您将向该函数发送 0x2。该函数可以读取那里的数据,但它没有引用 0x1 来更新 main.
中的 directory
变量
通过引用传递的一般规则是:如果你想更新函数中的引用以便调用者可以读取它,你需要传递一个比调用者中的变量多一个星号的星号。因此,如果您在 main 中有一个 int
,您可能希望在函数中更新一个 int*
。如果您在 main 中有一个 int***
,您可能想要更新一个 int****
.
对于初学者来说,这个代码片段
int nEntry = 0;
STUDENT* directory = malloc(nEntry * sizeof *directory);
if(directory == NULL){
puts("Unable to allocate memory");
exit(-1);
}
没有意义。参数等于 0 的 malloc 调用的行为是实现定义的。也就是说,这样的调用可以 return NULL 或某个有效指针,具体取决于所使用的系统。
写就够了
int nEntry = 0;
STUDENT* directory = NULL;
函数addNumber
处理传递参数值的副本。因此在函数内更改副本不会影响原始参数。
您必须通过引用传递原始参数。即通过指针指向指针。
void addNumber( STUDENT **Array, int *nArray );
^^^^^^^
此外,Array
和 nArray
等类似的参数名称使函数代码不可读。
函数可以通过以下方式声明
int addNumber( STUDENT **directory, int *n )
{
STUDENT *tempDirectory = realloc( *directory, ( *n + 1 ) * sizeof **directory );
if ( !tempDirectory ) return 0;
++*n;
*directory = tempDirectory;
// and so on
return 1;
}
并且调用者可以检查函数的 return 值是否以成功或失败结束,并在需要时发出相应的消息。
这些内存分配
Array[x].name = (char*)malloc(sizeof(char*));
Array[x].phoneNumber = (char*)malloc(sizeof(char*));
Array[x].department = (char*)malloc(sizeof(char*));
也说不通。你需要分配字符数组,你将在这样的调用中存储输入的字符串
scanf("%[^\n]", Array[x].name);
您可以声明一个辅助字符数组,例如
char s[100];
并读取此数组中的字符串。例如
printf("Name: ");
fgets( s, sizeof( s ), stdin );
s[ strcspn( s, "\n" ) ] = '[=17=]';
然后你可以为数据成员分配内存 name
知道读取字符串的长度
( *Array )[x].name = malloc( strlen( s ) + 1 );
并复制字符串
strcpy( ( *Array )[x].name, s );
我有一个包含 3 个字符指针(任意长度字符串)的结构,我用 malloc 创建了一个动态数组,因为它可以有任意数量的条目。 这是我的结构数据类型:
typedef struct student{
char* name;
char* phoneNumber;
char* department;
}STUDENT;
我使用一个函数重新分配以在需要新条目时增加结构数组的大小,并使用另一个函数打印整个数组。
我遇到的问题是: 我能够在 addNumber 函数内打印新条目,但当我尝试在 addNumber 函数外打印时,情况并非总是如此。有时它有效,大多数时候我遇到分段错误:11 并且有一次在添加新条目时我收到“malloc:对象 0x7fc426c058f0 的 *** 错误:未分配正在重新分配的指针”
这是我的主要内容:
int nEntry = 0;
STUDENT* directory = malloc(nEntry * sizeof *directory);
if(directory == NULL){
puts("Unable to allocate memory");
exit(-1);
}
while(1){
int choice = 0;
scanf("%d", &choice);
while(getchar() != '\n');
switch(choice){
case 1:
printDirectory(directory, nEntry);
break;
case 2:
addNumber(directory, &nEntry);
break;
default:
printf("Unknown option!\n");
break;
}
}
return 0;
这是我的 addNumber 函数:
void addNumber(STUDENT* Array, int* nArray){
*nArray += 1;
int x = *nArray - 1;
STUDENT* tempDirectory = realloc(Array, *nArray * sizeof *Array);
if(tempDirectory == NULL){
puts("Unable to allocate memory");
exit(-1);
}
else{
Array = tempDirectory;
Array[x].name = (char*)malloc(sizeof(char*));
Array[x].phoneNumber = (char*)malloc(sizeof(char*));
Array[x].department = (char*)malloc(sizeof(char*));
printf("Name: ");
scanf("%[^\n]", Array[x].name);
while(getchar() != '\n');
printf("Number: ");
scanf("%[^\n]", Array[x].phoneNumber);
while(getchar() != '\n');
printf("Department: ");
scanf("%[^\n]", Array[x].department);
while(getchar() != '\n');
for(int i = 0; i < *nArray; i++){
printf("%s\t%s\t(%s)\n", (Array + i)->name, (Array + i)->phoneNumber, (Array + i)->department);
}
}
}
这是我的打印功能:
void printDirectory(STUDENT* Array, int nArray){
int i;
for(i = 0; i < nArray; i++){
printf("%s\t%s\t(%s)\n", (Array + i)->name, (Array + i)->phoneNumber, (Array + i)->department);
}
}
如果我将条目硬编码到 main 中,打印函数工作正常,问题似乎是在 addNumber 函数中创建的内容没有正确传回?但是对于我通过引用传递的所有参数,我很困惑为什么我会得到一个未定义的行为。
正如评论中指出的那样,您的 malloc
大小不正确,因此您的代码还有其他问题,但要解决您对 realloc 的具体问题:
要存储 realloc
的 return 值以便可以在主函数中访问它,您需要传递指针的地址。
所以主要是:
addNumber(&directory, &nEntry); // Note the ampersand
并在 addNumber 中:
void addNumber(STUDENT** Array, int* nArray){ // Note the pointer to a pointer
...
STUDENT* tempDirectory = realloc(*Array, *nArray * sizeof *Array); // Note Array is dereferenced
...
*Array = tempDirectory;
...
如果您将 main 中的 directory
描绘为存储在位置 0x1 并指向内存位置 0x2 的变量,则在您当前的代码中,您将向该函数发送 0x2。该函数可以读取那里的数据,但它没有引用 0x1 来更新 main.
directory
变量
通过引用传递的一般规则是:如果你想更新函数中的引用以便调用者可以读取它,你需要传递一个比调用者中的变量多一个星号的星号。因此,如果您在 main 中有一个 int
,您可能希望在函数中更新一个 int*
。如果您在 main 中有一个 int***
,您可能想要更新一个 int****
.
对于初学者来说,这个代码片段
int nEntry = 0;
STUDENT* directory = malloc(nEntry * sizeof *directory);
if(directory == NULL){
puts("Unable to allocate memory");
exit(-1);
}
没有意义。参数等于 0 的 malloc 调用的行为是实现定义的。也就是说,这样的调用可以 return NULL 或某个有效指针,具体取决于所使用的系统。
写就够了
int nEntry = 0;
STUDENT* directory = NULL;
函数addNumber
处理传递参数值的副本。因此在函数内更改副本不会影响原始参数。
您必须通过引用传递原始参数。即通过指针指向指针。
void addNumber( STUDENT **Array, int *nArray );
^^^^^^^
此外,Array
和 nArray
等类似的参数名称使函数代码不可读。
函数可以通过以下方式声明
int addNumber( STUDENT **directory, int *n )
{
STUDENT *tempDirectory = realloc( *directory, ( *n + 1 ) * sizeof **directory );
if ( !tempDirectory ) return 0;
++*n;
*directory = tempDirectory;
// and so on
return 1;
}
并且调用者可以检查函数的 return 值是否以成功或失败结束,并在需要时发出相应的消息。
这些内存分配
Array[x].name = (char*)malloc(sizeof(char*));
Array[x].phoneNumber = (char*)malloc(sizeof(char*));
Array[x].department = (char*)malloc(sizeof(char*));
也说不通。你需要分配字符数组,你将在这样的调用中存储输入的字符串
scanf("%[^\n]", Array[x].name);
您可以声明一个辅助字符数组,例如
char s[100];
并读取此数组中的字符串。例如
printf("Name: ");
fgets( s, sizeof( s ), stdin );
s[ strcspn( s, "\n" ) ] = '[=17=]';
然后你可以为数据成员分配内存 name
知道读取字符串的长度
( *Array )[x].name = malloc( strlen( s ) + 1 );
并复制字符串
strcpy( ( *Array )[x].name, s );