您的直接问题是尝试将值分配给无效的内存位置。您的声明:
department *arr[N];
声明一个 指向 struct DEPARTMENT [N] 的指针数组(例如 5 个指向 struct 的指针)。然而,这些指针中的每一个都未初始化并指向一个不确定的内存位置。请记住,指针只是一个普通变量,它保存其他东西的地址作为它的值,就像一个普通变量一样,它在分配一个值之前保存一个不确定的值。
就像声明的任何其他局部变量一样,在值不确定时访问该值的任何尝试都会导致未定义行为。要使用指针数组,必须将每个指针的起始地址分配给有效的内存块作为其值。在这里,由于您的意图是为N 结构提供存储,因此无需声明N 指针,然后为N 结构单独分配存储。您可以简单地声明一个 指向 struct 的指针,然后在单个内存块中为 N struct 分配存储空间,例如
#define N 5
...
typedef struct {
char code[MAXC];
int sales;
} department;
...
department *arr; /* declares a pointer to struct */
...
/* allocate/validate storage for N struct */
if ((arr = malloc (N * sizeof *arr)) == NULL) {
perror ("malloc-arr");
return 1;
}
(注意:总是验证每次分配)
在单个块中为N 结构分配存储具有提供单个free() 以释放分配的内存块的优点。
正如您必须验证每个分配,您必须验证每个用户输入。这意味着至少,您必须验证每个都返回到scanf。但是,您使用scanf 有一个缺点。使用scanf 的输入非常脆弱,因为输入的任何变化都会导致匹配 失败,从stdin 提取字符将在匹配 失败发生时停止,离开stdin 中的冒犯角色未读 正等着下次打电话给 scanf 时再次咬你。此外,如果在有效输入之后有任何无意的字符,它们也会留在stdin 中未读。
您的选择是在每次输入后清空stdin,以确保没有剩余的违规字符,或者,更好的选择是每次使用面向行的输入函数读取完整的输入行像 fgets() 或 POSIX getline() 然后从填充的缓冲区中解析您需要的值。这有很多好处。每次输入都会读取并丢弃任何无关的字符。您还可以从能够独立验证 (1) 读取中受益; (2) 从缓冲区解析所需信息。您可以使用sscanf 解析填充缓冲区中的信息,就像使用scanf 从stdin 读取信息一样。
总而言之,您可以重写代码,如下所示:
#include <stdio.h>
#include <stdlib.h>
#define N 5
#define CODESZ 12 /* if you need more than 1 constant, define them */
#define MAXC 1024 /* (don't skimp on buffer size) */
typedef struct {
char code[MAXC];
int sales;
} department;
int main()
{
department *arr; /* declares a pointer to struct */
char buf[MAXC]; /* buffer to hold each line */
int i, ndx = 0;
/* allocate/validate storage for N struct */
if ((arr = malloc (N * sizeof *arr)) == NULL) {
perror ("malloc-arr");
return 1;
}
printf("Enter values for %d departments:\n", N);
while (ndx < N) { /* loop until info for N departments received */
printf ("\nThe %d department-\n Code : ", ndx + 1);
if (fgets (buf, MAXC, stdin) == NULL ||
sscanf (buf, "%11s", arr[ndx].code) != 1)
break;
fputs (" Sales : ", stdout);
if (fgets (buf, MAXC, stdin) == NULL ||
sscanf (buf, "%d", &arr[ndx].sales) != 1)
break;
ndx++;
}
puts ("\nDepartment Sales Results:\n");
for (i = 0; i < ndx; i++) /* output results, free memory */
printf ("Dept Code: %-12s Sales: %d\n", arr[i].code, arr[i].sales);
free (arr); /* don't forget to free what you allocate */
}
(注意:使用了一个单独的索引计数器ndx,即使用户在输入后取消输入,它也提供填充的实际结构数的计数,例如 3 个部门而不是 5 个)
使用/输出示例
$ ./bin/allocstructloop
Enter values for 5 departments:
The 1 department-
Code : 001
Sales : 123
The 2 department-
Code : 002
Sales : 234
The 3 department-
Code : 003 -- this department met sales goals.
Sales : 345
The 4 department-
Code : 004
Sales : 456 -- this department exceeded sales goals.
The 5 department-
Code : 005 -- this department had most sales for period.
Sales : 567
Department Sales Results:
Dept Code: 001 Sales: 123
Dept Code: 002 Sales: 234
Dept Code: 003 Sales: 345
Dept Code: 004 Sales: 456
Dept Code: 005 Sales: 567
在您输入后尝试输入额外的文本(甚至是额外的击键),看看您的代码如何响应。保持 Ctrl+C 处于就绪状态。
查看一下,如果您还有其他问题,请告诉我。