将结构数组传递给c编程中的函数

时间:2015-04-10 12:51:10

标签: c arrays function structure

我对C非常陌生并且苦苦挣扎。我遍布整个地方,无法找到任何我能理解或符合我疑问的内容。我的任务是创建一个数组,其中包含有关使用结构的6人的详细信息。然后,我必须创建一个菜单系统,允许某人搜索性别,名字,姓氏,出生日期和开始日期。

这是我的.h文件:

#define NAME_LENGTH 50

struct strDate
{
    int nDay;
    int nMnth;
    int nYear;
};

struct strPerson
{
    char    arcFirstName[NAME_LENGTH];
    char    arcLastName[NAME_LENGTH];
    char    cSex;
    struct  strDate    strDOB;
    struct  strDate    strStartDate;
};

这是我的.c文件(为了在这里保持代码最小化,我已经取出了除了一个结构定义之外的所有结构定义。数组的元素1-5与元素0非常相似,只有实际数据不同):

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include "Header.h"

/*Function prototypes*/
void Gender(struct strPerson *arPeople[5]);
void FirstName(struct strPerson *arPeople[5]);
void Surname(struct strPerson *arPeople[5]);
void Name(struct strPerson *arPeople[5]);
void YearOfBirth(struct strPerson *arPeople[5]);
void WholeDOB(struct strPerson *arPeople[5]);
void DOB(struct strPerson *arPeople[5]);
void YearOfStart(struct strPerson *arPeople[5]);

int main(void)
{
    int nChoice = 1;
    struct strPerson arPeople[5];

    /*populating structure within array "arPeople"*/
    strcpy(arPeople[0].arcFirstName, "David");
    strcpy(arPeople[0].arcLastName, "Hodgkiss");
    arPeople[0].cSex = 'M';
    arPeople[0].strDOB.nDay = 13;
    arPeople[0].strDOB.nMnth = 5;
    arPeople[0].strDOB.nYear = 1964;
    arPeople[0].strStartDate.nDay = 1;
    arPeople[0].strStartDate.nMnth = 9;
    arPeople[0].strStartDate.nYear = 2001;

    while (nChoice != 5)
    {
        printf("\nPlease enter number relating to search option required...\n");
        printf("1   Search by Gender\n");
        printf("2   Search by Name\n");
        printf("3   Search by Date of Birth\n");
        printf("4   Search by Start Date\n");
        printf("5   Exit\n\n");
        printf("Please enter your choice : ");
        scanf("%d", &nChoice);
        printf("\n");

        switch (nChoice)
        {
        case 1: Gender(arPeople);
            break;

        case 2: Name(arPeople);
            break;

        case 3: DOB(arPeople);
            break;

        case 4: YearOfStart(arPeople);
            break;

        case 5: break;

        default: printf("Invalid input, please try again : \n\n");
        }
    }

    system("pause");
    return 0;
}

void Gender(struct strPerson *arPeople[5])
{
    char cSexMF = 'M';

    printf("Please enter 'M' to search for male members of staff or 'F' to search for female memebers of staff : \n\n");
    scanf("%c \n", &cSexMF);

    printf(".... %c ... %c ....\n", cSexMF, arPeople[0].cSex);
} 

所以这显然只是按性别搜索...我的问题是:

  1. 如何在菜单系统中调用main中的功能?目前我一直收到错误&#34;警告C4047:&#39;功能&#39; :&#39; strPerson **&#39;不同的间接水平来自&#39; strPerson [5]&#39;&#34;。我完全不知道这意味着什么。

  2. 假设我已正确地将其传递给函数,那么如何从数组中打印任何内容?我在上面尝试打印arPeople[0].cSex时,它表示&#34;表达式必须具有结构或联合类型&#34;。我不明白这一点,因为我认为我已将它作为一个结构传递,所以它会知道我所引用的内容。

  3. 我非常感谢这方面的一些帮助,我看到了我能想到的所有地方,搜索了我能想到的一切,但我仍然无法使它发挥作用。我已经在这里待了好几天试图解决这个问题,并且如果我的课不及格,我甚至不在乎。

3 个答案:

答案 0 :(得分:2)

为什么使用指针数组?而不是:

void Gender(struct strPerson *arPeople[5])
{
    char cSexMF = 'M';

    printf("Please enter 'M' to search for male members of staff or 'F' to search for female memebers of staff : \n\n");
    scanf("%c \n", &cSexMF);

    printf(".... %c ... %c ....\n", cSexMF, arPeople[0].cSex);
}

执行此操作(这通常是将数组作为C中的参数传递给函数的方式):

void Gender(struct strPerson arPeople[], int arrLength)
{
    // Enter search criteria
    char cSexMF = 0;
    printf("Please enter 'M' to search for male members of staff or 'F' to search for female memebers of staff : \n\n");
    scanf(" %c", &cSexMF);

    // Go through array
    for(int i = 0; i<arrLength; i++)
    { 
      // Check gender of each element of array against what user entered
      if(arPeople[i].cSex == cSexMF)
      {
        printf(".... %c ... %c .... %s\n", cSexMF, arPeople[i].cSex, arPeople[i].arcFirstName);
      }
    }
}

这应该打印性别与用户输入的人匹配的姓名和性别;你可以将这种技术应用到你的其他方法中,就像我说我怀疑你需要使用这个结构:struct strPerson *arPeople[5],在你的情况下。

答案 1 :(得分:0)

让我们从基础知识开始:在评估表达式时,在C / C ++中,&#34;最大的咀嚼&#34;规则适用,尽可能正确,仍然得到有效的表达,然后向左走。

这是如何适用的?让我们评估您的数据声明

struct strPerson *arPeople[5] 
  1. 从您的变量开始:arPeople
  2. 右:arPeople是一个包含5个元素arPeople[5]
  3. 的数组
  4. 离开,因为你不能再向右走了:你有一个由5个元素组成的数组,它们是指针*arPeople[5]
  5. 右:您有一个指向strPerson strPerson *arPeople[5]
  6. 的5个指针数组

    现在,回到你的问题:数组被编译器处理为与指针相同;采取以下声明:

    int *p0;
    int p1[20];
    

    p0和p1都是从编译器的角度来看的指针:p0 [0]和p1 [1]代表第一个元素,p0 ++ / p1 ++增加地址,依此类推。这并不是说指针与数组相同,它们只是对待它们。

    当你想传入一个数组作为参数时,下面的函数原型做同样的事情:

    void foo(int* p);
    void foo(int p[]);
    void foo(int p[10]);
    

    编译器将为它们生成完全相同的代码,从它的角度来看,您将地址传递给数据块的开头。

    如果你想修改数组struct strPerson arPeople[5],那么你的函数原型应该只是:

    void Gender(struct strPerson *arPeople);
    OR
    void Gender(struct strPerson arPeople[]);
    

    出于上述所有原因。

    希望这有助于澄清事情......

答案 2 :(得分:0)

除非它是sizeof或一元&运算符的操作数,或者是用于在声明中初始化另一个数组的字符串文字,表达式为类型&#34; T&#34;的N元素数组;将被转换(&#34;衰减&#34;)到类型为&#34的表达式;指向T&#34;的指针,并且表达式的值将是第一个元素的地址。阵列。

此外,在函数参数声明的上下文中,T a[]T a[N]形式的声明将被视为T *

在函数调用中

Gender(arPeople);

表达式arPeople是从struct strPerson&#34;的类型&#34; 5元素数组转换而来的to&#34;指向struct strPerson&#34;或struct strPerson *

因此,您的函数声明和定义需要写成

void Gender( struct strPerson *arPeople )

在您的代码中,您将arPeople参数声明为指针数组,根据上面的第二条规则将其视为指向指针的指针,这是您的错误所在消息来自。请注意,您可以在指针表达式上使用下标运算符[],因此您仍然可以编写类似

的表达式
printf(".... %c ... %c ....\n", cSexMF, arPeople[0].cSex); 

可以传递一个实际的指向数组的指针,如下所示:

Gender( &arPeople );

因为在这种情况下,表达式arPeople是一元&运算符的操作数,所以它不会被转换为指针类型;表达式&arPeople的类型是&#34;指向struct strPerson&#34;或struct strPerson (*)[5]的5元素数组的指针。在这种情况下,您的函数声明和定义需要写为

void Gender( struct strPerson (*arPeople)[5] )

我不建议这样做有两个原因。首先,你的函数只能处理5个元素的数组,这个数组并不是非常灵活(指向5个元素的指针与指向某个数字的指针不兼容 - 不是 - 5元素阵列)。其次,在代码正文中,必须在应用下标之前取消引用指针,如下所示:

printf(".... %c ... %c ....\n", cSexMF, (*arPeople)[0].cSex); 
                                        ^^^^^^^^^^^
老实说,这会让事情变得混乱。

一些风格笔记:

您不希望传递数组而不传递其大小,因为接收函数只获取指向第一个元素的指针,而不是实际的数组对象。我建议您更改函数以获取其他大小参数:

void Gender( struct strPerson *arPeople, size_t arSize )

并将其命名为

Gender( arPeople, sizeof arPeople / sizeof *arPeople );

这样,您的Gender函数就知道数组中有多少元素。

其次,为了便于维护,您可以在main函数之前定义函数,如下所示:

void Gender( struct strPerson *arPeople, size_t arSize )
{
  // code for Gender function
}

void Surname( struct strPerson *arPeople, size_t arSize )
{
  // code for Surname function
}
...
int main( void ) 
{
  // code for main function
}

这样您就不必担心保持函数声明和定义同步。它确实让你的代码被读取&#34;向后&#34;但是相信我,从维护的角度来看,这会使事情变得更加简单。