我正在尝试制作一个管理学生信息的程序。但由于缺乏我的c编程技巧,我不能很好地使用指针。
以下是源代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
int id;
char fName[8];
char lName[8];
} Student;
void main()
{
int size = 0;
int i = 0;
/* get max lines */
scanf("%d", &size);
Student *students = (Student*) malloc(sizeof(Student) * size); // allocate whole table
Student *pointAt = students; // pointer used to point whole table by memory address
/* retrieves data from stdin */
for (i = 0; i < size; i++)
{
scanf("%d", &((*pointAt).id));
printf("recorded id at %d is %d\n", i, (*pointAt).id);
fgets((*pointAt).fName, sizeof((*pointAt).fName), stdin);
printf("recorded fName at %d is %s\n", i, (*pointAt).fName);
fgets((*pointAt).lName, sizeof((*pointAt).lName), stdin);
printf("recorded lName at %d is %s\n", i, (*pointAt).lName);
while (getchar() != '\n')
;
}
free(students);
}
我读取的文本文件名为test.txt:
2
11223344 Jennifer Smith
22334455 John Bob
*请注意,第一行中的2用于设置动态分配的struct的大小,用于:Student students =(Student )malloc(sizeof(Student)* size);因为只有2名学生,珍妮弗和约翰。
这是我跑来测试的命令:
a.out < test.txt
这是输出:
recorded id at 0 is 11223344
recorded fName at 0 is Jennif
recorded lName at 0 is er Smit
recorded id at 1 is 22334455
recorded fName at 1 is John B
recorded lName at 1 is ob
^Z
Suspended
问题是:
它似乎很好地检索了studentID,但没有找到名字(fName)和姓氏(lName)。似乎fName也会检索空间,它应该避免使用。
由于使用“while(getchar()!='\ n'),程序进入无限循环;”清除输入缓冲区。所以我按了ctrl + z(^ Z)强制终止程序,你可以在我的示例输出中看到。
我该如何解决这个问题?非常感谢..
首次修复后更改了部分来源:
for(i=0; i<size; i++) {
scanf("%d", &((*pointAt).id));
printf("recorded id at %d is %d\n", i, (*pointAt).id);
getchar();
fgets((*pointAt).fName, sizeof((*pointAt).fName), stdin);
printf("recorded fName at %d is %s\n", i, (*pointAt).fName);
getchar();
fgets((*pointAt).lName, sizeof((*pointAt).lName), stdin);
printf("recorded lName at %d is %s\n", i, (*pointAt).lName);
}
首次修复后输出:
recorded id at 0 is 11223344
recorded fName at 0 is Jennifer
recorded lName at 0 is Smith
recorded id at 1 is 22334455
recorded fName at 1 is John Bob
recorded lName at 1 is Smith
答案 0 :(得分:1)
尝试解决这两个问题:
fgets
也将'\ 0'视为另一个角色。
所以它认为“jennifer \ 0”长9个字符。所以增加
fname的大小为9个字符以容纳整个字符串。getchar()
消费它。答案 1 :(得分:1)
fgets
正是您所要求的。您传递并声明一个包含八个字符的缓冲区。之前的读数是scanf %d
,所以它已停在第一个非数字字符,这里是空格。然后输入流定位在Jenniffer...
上(注意初始空格字符!)。 fgets
读取7个字符并在第8个位置放置一个终止空值,它给出:
1 2 3 4 5 6 7 8
J e n n i f \0
如何解决?停止混合fgets
和scanf
...并增加缓冲区的大小。由于最长的名字是Jennifer(8个字符),因此最小大小为9以包括终止空值。并且还要避免那种可怕的黑客攻击:while (getchar() != '\n';
如果文件未被\n
终止或者\n
被fgets
吃掉,则可以保证导致无限循环1}}
最后但并非最不重要的是,控制输入函数的返回值,如scanf。还需要main来返回int而不是void,而malloc返回值永远不应该在C ...
中输入固定代码可能如下所示:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
int id;
char fName[12];
char lName[12];
} Student;
int main()
{
int size = 0;
int i = 0;
/* get max lines */
int cr = scanf("%d", &size);
if (cr != 1) {
fprintf(stderr, "Incorrect size");
return 1;
}
Student *students = malloc(sizeof(Student) * size); // allocate whole table
Student *pointAt = students; // pointer used to point whole table by memory address
/* retrieves data from stdin */
for (i = 0; i < size; i++)
{
cr = scanf("%d%11s%11s", &(pointAt->id),pointAt->fName, pointAt->lName);
if (cr != 3) {
fprintf(stderr, "Incorrect format line %d\n", i+1);
return 1;
}
printf("recorded id at %d is %d\n", i, (*pointAt).id);
printf("recorded fName at %d is %s\n", i, (*pointAt).fName);
printf("recorded lName at %d is %s\n", i, (*pointAt).lName);
pointAt += 1; // point to next struct in array
}
free(students);
return 0;
}
答案 2 :(得分:1)
您实际上并不需要再使用一个变量&#39; pointAt&#39;。你可以很好地使用malloc&#39; ed结构的学生来做你的事情。即使你这样做,这也是一个很好的做法,可以做到这一点。在释放已分配的struct之后为NULL。
free(students);
pointAt = NULL;
return 0;