c中结构中的动态分配内存
Dynamically allocated memory in structure in c
我正在尝试创建两个列表,pros 和 cons,然后打印它们。
但是我不知道我做错了什么。
我试着用gdb在线调试程序,发现错误在函数fgets()。
#include <stdio.h>
#include <string.h>
typedef struct list{
char ** reason;
} list;
void printMenu();
void printList(list * myList, int len1);
int main(void)
{
int keepGoing = 0;
int choice = 0;
int i = 0;
int j = 0;
list * pros;
list * cons;
while (!keepGoing){
printMenu();
scanf("%d", &choice);
pros = (list*)malloc(sizeof(list));
cons = (list*)malloc(sizeof(list));
switch (choice){
case 1:
i++;
printf("Enter a reason to add to list PRO: ");
pros = (list*)realloc(pros, i*sizeof(list));
fgets(pros->reason[i], 50, stdin);
pros->reason[strcspn(pros->reason[i], "\n")] = 0;
break;
case 2:
j++;
cons = (list*)realloc(cons->reason, j*sizeof(list));
printf("Enter a reason to add to list CON: ");
fgets(cons->reason[j], 50, stdin);
cons->reason[strcspn(cons->reason[j], "\n")] = 0;
break;
case 3:
printf("PROS:\n");
printList(pros, i);
printf("CONS:\n");
printList(cons, j);
break;
case 4:
keepGoing = 1;
break;
default:
printf("Invalid value.");
keepGoing = 1;
}
}
free(pros);
free(cons);
getchar();
return 0;
}
void printList(list * reasons, int len1){
int i = 0;
for (i = 0; i < len1; i++){
printf("%s\n", reasons->reason[i]);
}
}
void printMenu(){
printf("Choose option:\n");
printf("1 - Add PRO reason\n");
printf("2 - Add CON reason\n");
printf("3 - Print reasons\n");
printf("4 - Exit\n");
}
你有问题
fgets(pros->reason[i], 50, stdin);
因为您想要使用 的内存无效。 pros->reason
没有指向有效的内存,所以你不能取消引用它,这会导致 undefined behavior.
在索引到 pros->reason
之前,您需要使 pros->reason
指向一个有效的内存位置。
之后,如果您希望 pros->reason[i]
s 用作 fgets()
的 destination,则还需要指向有效内存.
除此问题外,您还有另一个问题使此代码变得毫无意义,即在循环的每次迭代中调用 malloc()
。您只需要调用 malloc()
一次,即可获得由内存分配器函数分配的(指向内存的)指针,然后在循环内使用 realloc()
来 adjust到所需的内存。
无需动态分配这些:list * pros; list * cons;
。 pros = (list*)realloc(pros, i*sizeof(list));
这样的代码没有任何意义。
相反,将它们声明为普通变量。 list pros
。
您需要动态分配的是成员 pros.reason
。您需要分配一个它指向的指针数组,然后您需要分配各个数组。
有很多问题。以前的评论和答案仍然适用。
这是一个干净的解决方案。
- 列表结构现在是自包含的,无需跟踪单独变量中的字符串数
- 添加了独立
AddString
功能
- 不再是不必要的
malloc
s
- 所有分配的内存都被正确释放
- 删除了一些逻辑错误(
keepGoing
的反逻辑)
还有改进的余地。特别是内存分配函数没有错误检查。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct list {
int size; // number of strings
int chunksize; // current of chunk
char ** reason;
} list;
void printMenu();
void printList(list * reasons);
void freeList(list * l);
void AddString(list *l, const char *string);
int main(void)
{
int keepGoing = 1;
int choice = 0;
list pros = { 0 }; // = {0} initializes all fields to 0
list cons = { 0 };
while (keepGoing) {
printMenu();
scanf("%d", &choice);
char input[50];
fgets(input, sizeof(input), stdin); // absorb \n from scanf
switch (choice) {
case 1:
printf("Enter a reason to add to list PRO: ");
fgets(input, sizeof(input), stdin);
AddString(&pros, input); // Add string to pros
break;
case 2:
printf("Enter a reason to add to list CONS: ");
fgets(input, sizeof(input), stdin);
AddString(&cons, input); // Add string to cons
break;
case 3:
printf("PROS:\n");
printList(&pros);
printf("CONS:\n");
printList(&cons);
break;
case 4:
keepGoing = 0;
break;
default:
printf("Invalid value.");
keepGoing = 1;
}
}
freeList(&pros);
freeList(&cons);
getchar();
return 0;
}
#define CHUNKSIZE 10
void AddString(list *l, const char *string)
{
if (l->size == l->chunksize)
{
// resize the reason pointer every CHUNKSIZE entries
l->chunksize = (l->chunksize + CHUNKSIZE);
// Initially l->reason is NULL and it's OK to realloc a NULL pointer
l->reason = realloc(l->reason, sizeof(char**) * l->chunksize);
}
// allocate memory for string (+1 for NUL terminator)
l->reason[l->size] = malloc(strlen(string) + 1);
// copy the string to newly allocated memory
strcpy(l->reason[l->size], string);
// increase number of strings
l->size++;
}
void freeList(list * l) {
for (int i = 0; i < l->size; i++) {
// free string
free(l->reason[i]);
}
// free the list of pointers
free(l->reason);
}
void printList(list * l) {
for (int i = 0; i < l->size; i++) {
printf("%s\n", l->reason[i]);
}
}
void printMenu() {
printf("Choose option:\n");
printf("1 - Add PRO reason\n");
printf("2 - Add CON reason\n");
printf("3 - Print reasons\n");
printf("4 - Exit\n");
}
我正在尝试创建两个列表,pros 和 cons,然后打印它们。 但是我不知道我做错了什么。
我试着用gdb在线调试程序,发现错误在函数fgets()。
#include <stdio.h>
#include <string.h>
typedef struct list{
char ** reason;
} list;
void printMenu();
void printList(list * myList, int len1);
int main(void)
{
int keepGoing = 0;
int choice = 0;
int i = 0;
int j = 0;
list * pros;
list * cons;
while (!keepGoing){
printMenu();
scanf("%d", &choice);
pros = (list*)malloc(sizeof(list));
cons = (list*)malloc(sizeof(list));
switch (choice){
case 1:
i++;
printf("Enter a reason to add to list PRO: ");
pros = (list*)realloc(pros, i*sizeof(list));
fgets(pros->reason[i], 50, stdin);
pros->reason[strcspn(pros->reason[i], "\n")] = 0;
break;
case 2:
j++;
cons = (list*)realloc(cons->reason, j*sizeof(list));
printf("Enter a reason to add to list CON: ");
fgets(cons->reason[j], 50, stdin);
cons->reason[strcspn(cons->reason[j], "\n")] = 0;
break;
case 3:
printf("PROS:\n");
printList(pros, i);
printf("CONS:\n");
printList(cons, j);
break;
case 4:
keepGoing = 1;
break;
default:
printf("Invalid value.");
keepGoing = 1;
}
}
free(pros);
free(cons);
getchar();
return 0;
}
void printList(list * reasons, int len1){
int i = 0;
for (i = 0; i < len1; i++){
printf("%s\n", reasons->reason[i]);
}
}
void printMenu(){
printf("Choose option:\n");
printf("1 - Add PRO reason\n");
printf("2 - Add CON reason\n");
printf("3 - Print reasons\n");
printf("4 - Exit\n");
}
你有问题
fgets(pros->reason[i], 50, stdin);
因为您想要使用 的内存无效。 pros->reason
没有指向有效的内存,所以你不能取消引用它,这会导致 undefined behavior.
在索引到 pros->reason
之前,您需要使 pros->reason
指向一个有效的内存位置。
之后,如果您希望 pros->reason[i]
s 用作 fgets()
的 destination,则还需要指向有效内存.
除此问题外,您还有另一个问题使此代码变得毫无意义,即在循环的每次迭代中调用 malloc()
。您只需要调用 malloc()
一次,即可获得由内存分配器函数分配的(指向内存的)指针,然后在循环内使用 realloc()
来 adjust到所需的内存。
无需动态分配这些:list * pros; list * cons;
。 pros = (list*)realloc(pros, i*sizeof(list));
这样的代码没有任何意义。
相反,将它们声明为普通变量。 list pros
。
您需要动态分配的是成员 pros.reason
。您需要分配一个它指向的指针数组,然后您需要分配各个数组。
有很多问题。以前的评论和答案仍然适用。
这是一个干净的解决方案。
- 列表结构现在是自包含的,无需跟踪单独变量中的字符串数
- 添加了独立
AddString
功能 - 不再是不必要的
malloc
s - 所有分配的内存都被正确释放
- 删除了一些逻辑错误(
keepGoing
的反逻辑)
还有改进的余地。特别是内存分配函数没有错误检查。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct list {
int size; // number of strings
int chunksize; // current of chunk
char ** reason;
} list;
void printMenu();
void printList(list * reasons);
void freeList(list * l);
void AddString(list *l, const char *string);
int main(void)
{
int keepGoing = 1;
int choice = 0;
list pros = { 0 }; // = {0} initializes all fields to 0
list cons = { 0 };
while (keepGoing) {
printMenu();
scanf("%d", &choice);
char input[50];
fgets(input, sizeof(input), stdin); // absorb \n from scanf
switch (choice) {
case 1:
printf("Enter a reason to add to list PRO: ");
fgets(input, sizeof(input), stdin);
AddString(&pros, input); // Add string to pros
break;
case 2:
printf("Enter a reason to add to list CONS: ");
fgets(input, sizeof(input), stdin);
AddString(&cons, input); // Add string to cons
break;
case 3:
printf("PROS:\n");
printList(&pros);
printf("CONS:\n");
printList(&cons);
break;
case 4:
keepGoing = 0;
break;
default:
printf("Invalid value.");
keepGoing = 1;
}
}
freeList(&pros);
freeList(&cons);
getchar();
return 0;
}
#define CHUNKSIZE 10
void AddString(list *l, const char *string)
{
if (l->size == l->chunksize)
{
// resize the reason pointer every CHUNKSIZE entries
l->chunksize = (l->chunksize + CHUNKSIZE);
// Initially l->reason is NULL and it's OK to realloc a NULL pointer
l->reason = realloc(l->reason, sizeof(char**) * l->chunksize);
}
// allocate memory for string (+1 for NUL terminator)
l->reason[l->size] = malloc(strlen(string) + 1);
// copy the string to newly allocated memory
strcpy(l->reason[l->size], string);
// increase number of strings
l->size++;
}
void freeList(list * l) {
for (int i = 0; i < l->size; i++) {
// free string
free(l->reason[i]);
}
// free the list of pointers
free(l->reason);
}
void printList(list * l) {
for (int i = 0; i < l->size; i++) {
printf("%s\n", l->reason[i]);
}
}
void printMenu() {
printf("Choose option:\n");
printf("1 - Add PRO reason\n");
printf("2 - Add CON reason\n");
printf("3 - Print reasons\n");
printf("4 - Exit\n");
}