链表问题中字符串的动态分配
Dynamic allocation of a string in a linked list problem
我已经创建了 2 个函数,它们从一个文件中读取一些数据并将数据写入另一个文件,但是使用链表和在该列表中动态分配的字符串,但是我有一个我找不到的逻辑错误:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct product {
char id[6];
char *name;
int price;
struct product *next;
};
struct product *read(struct product *head, FILE *input) {
struct product *p, *q, *aux;
p = (struct product *)malloc(sizeof(struct product));
char aux_id[6];
char aux_name[20];
int aux_price;
fscanf(input, "%s %s %d", aux_id, aux_name, &aux_price);
strcpy(p->id, aux_id);
p->name = (char *)malloc(strlen(aux_name) * (sizeof(char)));
strcpy(p->name,aux_name);
p->price = aux_price;
p->next = NULL;
head = p;
while (fscanf(input, "%s %s %d", aux_id, aux_name, &aux_price) != EOF) {
q = (struct product *)malloc(sizeof(struct product));
q->name = (char *)malloc(strlen(aux_name) * (sizeof(char)));
q->next = NULL;
strcpy(q->name, aux_name);
strcpy(q->id, aux_id);
q->price = aux_price;
p->next = q;
p = q;
}
return head;
}
void write(struct product *head, FILE *output) {
struct product *p;
p = head;
while (p != NULL) {
fprintf(output, "%s %s %d\n", p->id, p->name, p->price);
p = p->next;
}
}
int main() {
struct product *head, *p, *q;
FILE *input = fopen("input.txt", "r+");
FILE *output = fopen("output.txt", "w+");
head = read(head, input);
write(head, output);
fclose(input);
fclose(output);
}
输入文件如下所示:
333444 Cola 3
332312 Pepsi 4
123451 Mountain 3
输出文件如下所示
333444 Cola 3
332312°)q 4
123451à)q 3
您的代码中存在多个问题:
您读取字符串的数组太小:6 个字节不足以存储 6 位数字的 ID,您需要 space 作为空终止符。结构定义中的相同问题。
因为您没有提供要存储到这些数组中的最大字节数,fscanf()
将空终止符存储在 aux_id
数组的末尾之后,导致未定义的行为这解释了输出。
参数 head
未在函数 read
中使用,并在 main()
中未初始化传递。
您没有为空终止符分配足够的 space。您应该使用:
p->name = malloc(strlen(aux_name) + 1);
strcpy(p->name, aux_name);
或者简单地说:
p->name = strdup(aux_name);
- 另请注意,将函数命名为
read
和 write
可能会导致问题,因为这些名称在 C 库中用于系统调用包装器。
- 无需打开文件进行更多更新:只需使用
"r"
和 "w"
。
- 您不检查
fopen()
或 malloc()
失败。
这是修改后的版本:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct product {
char id[7];
char *name;
int price;
struct product *next;
};
struct product *read(FILE *input) {
struct product *head = NULL, *tail = NULL, *p;
char buf[100];
char aux_id[7];
char aux_name[20];
int aux_price;
while (fgets(buf, sizeof buf, input)) {
if (sscanf(buf, "%6s %19s %d", aux_id, aux_name, &aux_price) != 3) {
fprintf(stderr, "line format error: %s", buf);
continue;
}
p = (struct product *)malloc(sizeof(struct product));
if (p == NULL) {
fprintf(stderr, "memory allocation failure");
break
}
strcpy(p->id, aux_id);
p->name = strdup(aux_name);
if (p->name == NULL) {
fprintf(stderr, "memory allocation failure");
free(p);
break;
}
p->price = aux_price;
p->next = NULL;
if (head == NULL) {
head = p;
} else {
tail->next = p;
}
tail = p;
}
return head;
}
void write(struct product *head, FILE *output) {
struct product *p = head;
while (p != NULL) {
fprintf(output, "%s %s %d\n", p->id, p->name, p->price);
p = p->next;
}
}
int main() {
struct product *head;
FILE *input = fopen("input.txt", "r");
if (input == NULL) {
fprintf(stderr, "cannot open input file\n");
return 1;
}
FILE *output = fopen("output.txt", "w");
if (output == NULL) {
fprintf(stderr, "cannot open output file\n");
return 1;
}
head = read(head, input);
write(head, output);
fclose(input);
fclose(output);
return 0;
}
strdup()
是大多数系统上可用的 POSIX 函数,将包含在下一版本的 C 标准中。如果你的系统没有,可以这样写:
#include <stdlib.h>
#include <string.h>
char *strdup(const char *s) {
size_t size = strlen(s) + 1;
char *p = malloc(size);
if (p == NULL)
return NULL;
return memcpy(p, s, size);
}
如果 char aux_id[6];
的长度为 6,则“332312”太大,您需要 space 终止符号 '\0' 才能与字符串函数一起使用。
这里有两个问题,都是因为没有考虑字符串的终止空字节。
由于没有留下足够的空间 space,您写入的内容超出了存储字符串的数组/分配内存的边界。这会触发 undefined behavior,它表现为您在输出文件中看到的乱码输出。
第一个在这里(在两个地方):
malloc(strlen(aux_name)*(sizeof(char)));
这应该是:
malloc(strlen(aux_name)*(sizeof(char)) + 1);
第二个在你的结构中,也在 read
:
char id[6];
应该是:
char id[7];
后一种情况最有可能是输出文件看起来如此的原因,因为在结构中写入/读取过去的 id
可能会踩到 name
。
此外,read
和write
是库函数的名称。您应该将它们重命名为与它们不冲突的其他名称。您还应该在使用完毕后释放分配的内存。
我已经创建了 2 个函数,它们从一个文件中读取一些数据并将数据写入另一个文件,但是使用链表和在该列表中动态分配的字符串,但是我有一个我找不到的逻辑错误:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct product {
char id[6];
char *name;
int price;
struct product *next;
};
struct product *read(struct product *head, FILE *input) {
struct product *p, *q, *aux;
p = (struct product *)malloc(sizeof(struct product));
char aux_id[6];
char aux_name[20];
int aux_price;
fscanf(input, "%s %s %d", aux_id, aux_name, &aux_price);
strcpy(p->id, aux_id);
p->name = (char *)malloc(strlen(aux_name) * (sizeof(char)));
strcpy(p->name,aux_name);
p->price = aux_price;
p->next = NULL;
head = p;
while (fscanf(input, "%s %s %d", aux_id, aux_name, &aux_price) != EOF) {
q = (struct product *)malloc(sizeof(struct product));
q->name = (char *)malloc(strlen(aux_name) * (sizeof(char)));
q->next = NULL;
strcpy(q->name, aux_name);
strcpy(q->id, aux_id);
q->price = aux_price;
p->next = q;
p = q;
}
return head;
}
void write(struct product *head, FILE *output) {
struct product *p;
p = head;
while (p != NULL) {
fprintf(output, "%s %s %d\n", p->id, p->name, p->price);
p = p->next;
}
}
int main() {
struct product *head, *p, *q;
FILE *input = fopen("input.txt", "r+");
FILE *output = fopen("output.txt", "w+");
head = read(head, input);
write(head, output);
fclose(input);
fclose(output);
}
输入文件如下所示:
333444 Cola 3
332312 Pepsi 4
123451 Mountain 3
输出文件如下所示
333444 Cola 3
332312°)q 4
123451à)q 3
您的代码中存在多个问题:
您读取字符串的数组太小:6 个字节不足以存储 6 位数字的 ID,您需要 space 作为空终止符。结构定义中的相同问题。
因为您没有提供要存储到这些数组中的最大字节数,
fscanf()
将空终止符存储在aux_id
数组的末尾之后,导致未定义的行为这解释了输出。参数
head
未在函数read
中使用,并在main()
中未初始化传递。您没有为空终止符分配足够的 space。您应该使用:
p->name = malloc(strlen(aux_name) + 1); strcpy(p->name, aux_name);
或者简单地说:
p->name = strdup(aux_name);
- 另请注意,将函数命名为
read
和write
可能会导致问题,因为这些名称在 C 库中用于系统调用包装器。 - 无需打开文件进行更多更新:只需使用
"r"
和"w"
。 - 您不检查
fopen()
或malloc()
失败。
这是修改后的版本:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct product {
char id[7];
char *name;
int price;
struct product *next;
};
struct product *read(FILE *input) {
struct product *head = NULL, *tail = NULL, *p;
char buf[100];
char aux_id[7];
char aux_name[20];
int aux_price;
while (fgets(buf, sizeof buf, input)) {
if (sscanf(buf, "%6s %19s %d", aux_id, aux_name, &aux_price) != 3) {
fprintf(stderr, "line format error: %s", buf);
continue;
}
p = (struct product *)malloc(sizeof(struct product));
if (p == NULL) {
fprintf(stderr, "memory allocation failure");
break
}
strcpy(p->id, aux_id);
p->name = strdup(aux_name);
if (p->name == NULL) {
fprintf(stderr, "memory allocation failure");
free(p);
break;
}
p->price = aux_price;
p->next = NULL;
if (head == NULL) {
head = p;
} else {
tail->next = p;
}
tail = p;
}
return head;
}
void write(struct product *head, FILE *output) {
struct product *p = head;
while (p != NULL) {
fprintf(output, "%s %s %d\n", p->id, p->name, p->price);
p = p->next;
}
}
int main() {
struct product *head;
FILE *input = fopen("input.txt", "r");
if (input == NULL) {
fprintf(stderr, "cannot open input file\n");
return 1;
}
FILE *output = fopen("output.txt", "w");
if (output == NULL) {
fprintf(stderr, "cannot open output file\n");
return 1;
}
head = read(head, input);
write(head, output);
fclose(input);
fclose(output);
return 0;
}
strdup()
是大多数系统上可用的 POSIX 函数,将包含在下一版本的 C 标准中。如果你的系统没有,可以这样写:
#include <stdlib.h>
#include <string.h>
char *strdup(const char *s) {
size_t size = strlen(s) + 1;
char *p = malloc(size);
if (p == NULL)
return NULL;
return memcpy(p, s, size);
}
如果 char aux_id[6];
的长度为 6,则“332312”太大,您需要 space 终止符号 '\0' 才能与字符串函数一起使用。
这里有两个问题,都是因为没有考虑字符串的终止空字节。
由于没有留下足够的空间 space,您写入的内容超出了存储字符串的数组/分配内存的边界。这会触发 undefined behavior,它表现为您在输出文件中看到的乱码输出。
第一个在这里(在两个地方):
malloc(strlen(aux_name)*(sizeof(char)));
这应该是:
malloc(strlen(aux_name)*(sizeof(char)) + 1);
第二个在你的结构中,也在 read
:
char id[6];
应该是:
char id[7];
后一种情况最有可能是输出文件看起来如此的原因,因为在结构中写入/读取过去的 id
可能会踩到 name
。
此外,read
和write
是库函数的名称。您应该将它们重命名为与它们不冲突的其他名称。您还应该在使用完毕后释放分配的内存。