从事家庭作业并获得错误我不明白

问题描述 投票:-2回答:2

我正在为一个“人”的结构制作一个typedef这个人有一个name, ssnyearOfBirth。我得到的错误我不理解我的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;
c
2个回答
1
投票

首先,它似乎是指针和引用任务。您可能需要阅读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)用于阅读(而不是编辑),因此您可以自己传递值。


0
投票

你有这么多小问题,很难知道从哪里开始。首先,当引用结构成员时,你永远不会在"->"周围包含空格。使用p->name,而不是p -> name。继续...

您无法验证scanf的返回。您必须检查每次返回,或者您正在诱惑未定义的行为。您还必须将"%99[^\n]"更改为" %79[^\n]",因为"%c""%[...]"都不会消耗前导空格。未能在" "之前添加%12[^\n]将使得无法阅读p->ssn并导致阅读p->yearOfBirth的匹配失败。

请注意从9979的变化。你#define NAME_SIZE 80和声明char name[NAME_SIZE];,当你最多99字符可以存储在79时,你认为你使用name的字段宽度修饰符做什么? (你和#define SSN_SIZE 13有同样的问题)。您可以将字段宽度修饰符与scanf一起使用来保护数组边界。将* field-width修饰符设置为大于数组大小(-1)将删除它应该提供的保护。

如果用户意外地在输入中出现单个错误,则无法检查scanf的返回并处理必要的三种返回情况将导致未定义的行为。未能检查scanf的返回是新C程序员陷入的最常见的陷阱之一。每个用户输入都是必需的。否则,您可能无法确信您的代码实际上正在处理有效数据。

如果使用正确,可以使用scanf。这意味着您每次都要负责检查scanf的返回。你必须处理三个条件

  1. (return == EOF)用户通过按Ctrl + d生成手动EOF取消输入(或在Windows Ctrl + z上,但请参阅CTRL+Z does not generate EOF in Windows 10 (early versions));
  2. (return < expected No. of conversions)发生匹配或输入故障。对于匹配失败,您必须考虑输入缓冲区中剩余的每个字符。 (在输入缓冲区中向前扫描并丢弃字符,直到找到'\n'EOF);最后
  3. (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

仔细看看,如果您有其他问题,请告诉我。

© www.soinside.com 2019 - 2024. All rights reserved.