我正在为一个“人”的结构制作一个typedef
这个人有一个name, ssn
和yearOfBirth
。我得到的错误我不理解我的for循环。
[Error] cannot convert 'person_t' to 'person_t*' for argument '1' to
'void getOnePerson(person_t*)'
这是第一个文件:
#include <stdio.h>
#include <string.h>
#include "structures.h"
void getOnePerson(person_t *p)
{
printf("Enter full name: ");
scanf("%99[^\n]", p -> name);
printf("Enter ssn: ");
scanf("%99[^\n]", p -> ssn);
printf("Enter year of birth: ");
scanf("%d", &p -> yearOfBirth);
}
void printOnePerson(person_t p)
{
printf("%s:", p.name);
printf("%s:", p.ssn);
printf("%s\n", p.yearOfBirth);
}
void getPeople(person_t p[], int numOfPeople)
{
for(int i = 0; i < sizeof(p); i++)
{
getOnePerson(p[i]);
}
}
void printPeople(person_t p[], int numOfPeople)
{
for(int i = 0; i < sizeof(p); i++)
{
printOnePerson(p[i]);
}
}
这是我的结构文件:
#define NAME_SIZE 80
#define SSN_SIZE 13
#define NUM_PEOPLE 10
typedef struct
{
char name[NAME_SIZE];
char ssn[SSN_SIZE];
int yearOfBirth;
} person_t;
首先,它似乎是指针和引用任务。您可能需要阅读this才能理解它们。换句话说,无法将person_t
转换为person_t*
意味着您正在尝试使用您的对象人而不是引用该特定人。 *
表示引用,因此您需要使用&
将地址传递给它。我不是最好的解释员,检查链接而不是所有答案,不仅接受一个。
代码看起来很乱,我试着把它修改为可编译的代码,虽然我没有C编译器(你可能需要根据你的作业细节编辑/修复):
#include <stdio.h>
#include <string.h>
#define NAME_SIZE 80
#define SSN_SIZE 13
#define NUM_PEOPLE 10
typedef struct
{
char name[NAME_SIZE];
char ssn[SSN_SIZE];
int yearOfBirth;
} person_t;
int main()
{
person_t people[NUM_PEOPLE];
printf("Get people\n");
getPeople(&people, 3);
printf("\nPrint people\n");
printPeople(people, 3);
return 0;
}
void getOnePerson(person_t *person)
{
printf("Enter full name: ");
scanf("%s", person -> name);
printf("\nEnter ssn: ");
scanf("%s", person -> ssn);
printf("\nEnter year of birth: ");
scanf("%s", person -> yearOfBirth);
}
void printOnePerson(person_t p)
{
printf("%s:%s:%d\n", p.name, p.ssn, p.yearOfBirth);
}
void getPeople(person_t *person[], int num)
{
int i;
for(i=0; i<num; i++)
{
getOnePerson(&person[i]);
}
}
void printPeople(person_t person[], int num)
{
int i;
for(i=0; i<num; i++)
{
printOnePerson(person[i]);
}
}
所以,简单地说,你的getPeople(person_t *person[], int num)
函数的第一个参数是person_t *person[]
,因此你需要传递一个&people
。与getOnePerson(person_t *person)
参数person_t *person
相同意味着您需要将地址传递给单个人对象&person[i]
。使用引用后面的含义,您可以直接在函数中编辑这些对象中的值。虽然printPeople(person_t person[], int num)
和printOnePerson(person_t p)
用于阅读(而不是编辑),因此您可以自己传递值。
你有这么多小问题,很难知道从哪里开始。首先,当引用结构成员时,你永远不会在"->"
周围包含空格。使用p->name
,而不是p -> name
。继续...
您无法验证scanf
的返回。您必须检查每次返回,或者您正在诱惑未定义的行为。您还必须将"%99[^\n]"
更改为" %79[^\n]"
,因为"%c"
或"%[...]"
都不会消耗前导空格。未能在" "
之前添加%12[^\n]
将使得无法阅读p->ssn
并导致阅读p->yearOfBirth
的匹配失败。
请注意从99
到79
的变化。你#define NAME_SIZE 80
和声明char name[NAME_SIZE];
,当你最多99
字符可以存储在79
时,你认为你使用name
的字段宽度修饰符做什么? (你和#define SSN_SIZE 13
有同样的问题)。您可以将字段宽度修饰符与scanf
一起使用来保护数组边界。将* field-width修饰符设置为大于数组大小(-1
)将删除它应该提供的保护。
如果用户意外地在输入中出现单个错误,则无法检查scanf
的返回并处理必要的三种返回情况将导致未定义的行为。未能检查scanf
的返回是新C程序员陷入的最常见的陷阱之一。每个用户输入都是必需的。否则,您可能无法确信您的代码实际上正在处理有效数据。
如果使用正确,可以使用scanf
。这意味着您每次都要负责检查scanf
的返回。你必须处理三个条件
(return == EOF)
用户通过按Ctrl + d生成手动EOF
取消输入(或在Windows Ctrl + z上,但请参阅CTRL+Z does not generate EOF in Windows 10 (early versions));(return < expected No. of conversions)
发生匹配或输入故障。对于匹配失败,您必须考虑输入缓冲区中剩余的每个字符。 (在输入缓冲区中向前扫描并丢弃字符,直到找到'\n'
或EOF
);最后(return == expected No. of conversions)
表示读取成功 - 然后由您来检查输入是否满足任何其他标准(例如正整数,正浮点,在所需范围内等)。在匹配失败的情况下清空stdin
中所有剩余字符的简短函数实现可以简单如下:
void empty_stdin (void)
{
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
(在你的代码中实现留给你的练习)
此外,使用类型void
作为输入函数的返回是没有意义的。您必须选择返回以提供所需信息的返回,并提供输入成功或失败的指示。将void
用于getOnePerson()
意味着您无法知道您是否收到了所有有效输入,或者只是收到了name
,而不是ssn
,或者用户只是在每次提示时生成了手动EOF
取消输入。您需要一个简单的整数返回(例如,在所有3输入都经过验证后,失败时return 0;
或return 1;
)您可以执行以下操作:
int getOnePerson (person_t *p)
{
int rtn; /* scanf return */
/* validate each input for all 3 cases */
fputs ("\nEnter full name: ", stdout); /* no need for printf, no conversion */
if ((rtn = scanf (" %79[^\n]", p->name)) != 1) {
if (rtn == EOF)
puts ("(input complete)");
else
fputs ("error: invalid format 'p->name'.\n", stderr);
return 0;
}
/* validate each input for all 3 cases */
fputs ("Enter ssn: ", stdout); /* ditto */
if ((rtn = scanf (" %12[^\n]", p->ssn)) != 1) { /* " */
if (rtn != EOF)
fputs ("error: invalid format 'p->ssn'.\n", stderr);
return 0;
}
/* validate each input for all 3 cases */
fputs ("Enter year of birth: ", stdout);
if ((rtn = scanf ("%d", &p->yearOfBirth)) != 1) {
if (rtn != EOF)
fputs ("error: invalid format 'p->yearOfBirth'.\n", stderr);
return 0;
}
return 1; /* indicates all 3 input successfully received */
}
(注意:遇到EOF
时输入完成,由用户手动生成或在输入流中遇到)
void
作为getPeople()
的回归也毫无意义。您不能使用for
循环并假设所有输入都成功,相反,您只需在输入可用时获取输入,同时保护您的数组边界,然后返回实际接收的输入数量(可能小于NUM_PEOPLE
)。此外,正确选择您的类型。对于柜台,size_t
是正确的类型(你不能有负数的人),例如
size_t getPeople (person_t *p, size_t numOfPeople)
{
// for(int i = 0; i < sizeof(p); i++)
// {
// getOnePerson(p[i]);
// }
size_t n = 0;
while (n < numOfPeople && getOnePerson (&p[n]))
n++;
return n;
}
将数组作为参数传递给函数时,数组将转换为指向第一个元素的指针。所以当你在一个函数中执行sizeof(p)
时 - 这不是你想要的并且不提供p
引用的数组中的元素数量 - 它提供的是sizeof(a_pointer)
,它由编译器修复(例如8字节)在x86_64上,x86上有4个字节)。你通过numOfPeople
- 使用它,例如
void printPeople (person_t *p, size_t numOfPeople)
{
puts ("\nStored People\n");
// for(int i = 0; i < sizeof(p); i++)
for (size_t i = 0; i < numOfPeople; i++)
{
printOnePerson(p[i]);
}
}
您还需要修复printf("%s\n", p.yearOfBirth);
(yearOfBirth
不是字符串...)
你的标题很好,但它遗漏了一些东西。始终在头文件的内容周围添加标题保护,以防止文件的多个包含,例如,
#ifndef mystructures_h
#define mystructures_h 1
...
/* your header content */
...
#endif
(注意:1
不是必需的,但是如果你定义一个常数,那么给它一个肯定的价值绝不是一个坏主意)
可能还有更多内容得到纠正,但这些都是重点。完全放在一起,你可以这样做:
structures.h
#ifndef mystructures_h
#define mystructures_h 1
#include <stdio.h>
#define NAME_SIZE 80
#define SSN_SIZE 13
#define NUM_PEOPLE 10
typedef struct {
char name[NAME_SIZE];
char ssn[SSN_SIZE];
int yearOfBirth;
} person_t;
size_t getPeople (person_t *p, size_t numOfPeople);
void printPeople (person_t *p, size_t numOfPeople);
#endif
(你能弄明白为什么#include <stdio.h>
从structures.c
转移到structures.h
吗?你知道为什么getPeople()
和printPeople()
的函数原型在标题中是必需的而不是其余的吗?)
structures.c
#include "structures.h"
int getOnePerson (person_t *p)
{
int rtn; /* scanf return */
fputs ("\nEnter full name: ", stdout);
if ((rtn = scanf (" %79[^\n]", p->name)) != 1) {
if (rtn == EOF)
puts ("(input complete)");
else
fputs ("error: invalid format 'p->name'.\n", stderr);
return 0;
}
fputs ("Enter ssn: ", stdout); /* ditto */
if ((rtn = scanf (" %12[^\n]", p->ssn)) != 1) { /* " */
if (rtn != EOF)
fputs ("error: invalid format 'p->ssn'.\n", stderr);
return 0;
}
fputs ("Enter year of birth: ", stdout);
if ((rtn = scanf ("%d", &p->yearOfBirth)) != 1) {
if (rtn != EOF)
fputs ("error: invalid format 'p->yearOfBirth'.\n", stderr);
return 0;
}
return 1;
}
size_t getPeople (person_t *p, size_t numOfPeople)
{
// for(int i = 0; i < sizeof(p); i++)
// {
// getOnePerson(p[i]);
// }
size_t n = 0;
while (n < numOfPeople && getOnePerson (&p[n]))
n++;
return n;
}
void printOnePerson (person_t p)
{
printf("%s:", p.name);
printf("%s:", p.ssn);
// printf("%s\n", p.yearOfBirth);
printf("%d\n", p.yearOfBirth);
}
void printPeople (person_t *p, size_t numOfPeople)
{
puts ("\nStored People\n");
// for(int i = 0; i < sizeof(p); i++)
for (size_t i = 0; i < numOfPeople; i++)
{
printOnePerson(p[i]);
}
}
一个简短的测试程序peopletest.c
#include "structures.h"
int main (void) {
person_t people[NUM_PEOPLE] = {{ .name = "" }};
size_t npeople = getPeople (people, NUM_PEOPLE);
printPeople (people, npeople);
}
示例使用/输出
$ ./bin/peopletest
Enter full name: Person A. One
Enter ssn: 123456789
Enter year of birth: 2001
Enter full name: Person B. Two
Enter ssn: 234567890
Enter year of birth: 2002
Enter full name: Person C. Three
Enter ssn: 345678901
Enter year of birth: 2003
Enter full name: (input complete)
Stored People
Person A. One:123456789:2001
Person B. Two:234567890:2002
Person C. Three:345678901:2003
仔细看看,如果您有其他问题,请告诉我。