把外部变量局部于main函数内遇到了问题

当被调用函数用局部于main函数内的变量作为参数时。出现了问题。因为被调用函数的作用是改变参数的值,所以考虑用指针作为参数。但是struct part q【】(之前是外部变量)是一个存放结构的数组。(结构包含商品的编号,名称,数量三项元素)所以,指向数组元素(结构)的指针怎么声明?当我想要逐项添加或修改结构的三个内容时,又改怎么写?以下是“插入商品”的函数。
void insert(struct part *q,int n)//两个参数是被要求局部于main函数中的外部变量
{
int i=0,part_number;
if(n==MAX_PARTS){
printf("Database is full;can't add more parts.\n");
return;
}
printf("Enter part number:");
scanf("%d",&part_number);
if(find_part(part_number,q,n)>=0){
printf("Part already exists.\n");
return;
}
*q.number=part_number;
printf("Enter part name:");
read_line(*q.name,NAME_LEN);
printf("Enter quantity on hand:");
scanf("%d",*q.on_hand);
n++;
}

*q.number和q[n].number的写法都不对。

#include

typedef struct
{
int x;
} *A;

void foo(A* a)
{
printf("%d", a[0]->x);
}

int main()
{
A a[2];
a[0]->x = 123;
foo(a);
}

q[n]->number

lz能不能不要胡乱采纳,昨天莫名其妙就采纳给一个瞎灌水的

 #include <stdio.h>

typedef struct
{
    int x;
} *A;

void foo(A* a)
{
printf("%d", a[0]->x);
}

int main()
{
    A a[2];
    a[0]->x = 123;
    foo(a);
}

123

https://c.runoob.com/compile/11 在线验证。

(1)用结构体变量名作为参数。

复制代码 代码如下:

#include
#include
using namespace std;
struct Student{
string name;
int score;
};
int main(){
Student one;
void Print(Student one);
one.name="千手";
one.score=99;
Print(one);
cout<<one.name<<endl;
cout<<one.score<<endl;//验证 score的值是否加一了
return 0;
}
void Print(Student one){
cout<<one.name<<endl;
cout<<++one.score<<endl;//在Print函数中,对score进行加一
}

这种方式值采取的“值传递”的方式,将结构体变量所占的内存单元的内存全部顺序传递给形参。在函数调用期间形参也要占用内存单元。这种传递方式在空间和实践上开销较大,如果结构体的规模很大时,开销是很客观的。
并且,由于采用值传递的方式,如果在函数被执行期间改变了形参的值,该值不能反映到主调函数中的对应的实参,这往往不能满足使用要求。因此一般较少使用这种方法。

(2)用指向结构体变量的指针作为函数参数

复制代码 代码如下:

#include
#include
using namespace std;
struct Student{
string name;
int score;
};
int main(){
Student one;
void Print(Student *p);
one.name="千手";
one.score=99;
Student *p=&one;
Print(p);
cout< cout return 0;
}
void Print(Student *p){
coutname< coutscore<<endl;//在Print函数中,对score进行加一
}

这种方式虽然也是值传递的方式,但是这次传递的值却是指针。通过改变指针指向的结构体变量的值,可以间接改变实参的值。并且,在调用函数期间,仅仅建立了一个指针变量,大大的减小了系统的开销。
(3)用接头体变量的引用变量作函数参数

复制代码 代码如下:

#include
#include
using namespace std;
struct Student{
string name;
int score;
};
int main(){
Student one;
void Print(Student &one);
one.name="千手";
one.score=99;
Print(one);
cout<<one.name<<endl;
cout<<one.score<<endl;//验证 score的值是否加一了
return 0;
}
void Print(Student &one){
cout<<one.name<<endl;
cout<<++one.score<<endl;//在Print函数中,对score进行加一
}

// 员工信息结构体

typedef struct

{

   INT8       szEmployeeName[100];     // 员工姓名

   UINT16  iEmployeeAge;                    // 员工年龄

   UINT32  iEmployeeNo;                      // 员工工号

} TEmployeeInfo;

    函数GetEmployeeInfo用来对员工信息字段进行赋值,其声明如下:

INT32 GetEmployeeInfo(TEmployeeInfo *ptEmployeeInfo);

   在主函数main中,采用两种参数传递的方法,一种是指针传递,另一种是非指针传递。

二、采用指针传递时的程序代码
采用指针传递时的程序代码如下:

/**********************************************************************

  • 版权所有 (C)2014, Zhou Zhaoxiong。

*

  • 文件名称: TestStruct.c

  • 文件标识:无

  • 内容摘要:用于演示结构体变量的用法

  • 其它说明:无

  • 当前版本: V1.0

  • 作 者:周兆熊

  • 完成日期: 20140617

*

  • 修改记录1:// 修改历史记录, 包括修改日期、版本号、修改人及修改内容

  • 修改日期: 20140617

  • 版本号: V1.0

  • 修改人: Zhou Zhaoxiong

  • 修改内容:创建

**********************************************************************/

#include

#include

// 数据类型

typedef signed char INT8;

typedef unsigned char UINT16;

typedef unsigned int UINT32;

typedef signed int INT32;

// 员工信息结构体

typedef struct

{

   INT8    szEmployeeName[100];  // 员工姓名

   UINT16  iEmployeeAge;         // 员工年龄

   UINT32  iEmployeeNo;          // 员工工号

} TEmployeeInfo;

// 函数声明

INT32 GetEmployeeInfo(TEmployeeInfo *ptEmployeeInfo); // 获取员工信息函数

INT32 main(void);

/****************************************************************

  • 功能描述: 主函数

  • 输入参数: 无

  • 输出参数: 无

  • 返回值: 0-执行成功 -1-执行失败

  • 其他说明: 无

  • 修改日期 版本号 修改人 修改内容


  • 20140617 V1.0 Zhou Zhaoxiong 创建

****************************************************************/

INT32 main(void)

{

INT32          iRetValue      = 0;       // 该变量用于表示调用GetEmployeeInfo函数返回的值

TEmployeeInfo *ptEmployeeInfo = NULL;    // 该变量用于存放员工信息



// 调用函数对员工信息字段赋值, 并打印出来

iRetValue = GetEmployeeInfo(ptEmployeeInfo);

if (iRetValue != 0)

{

    printf("exec GetEmployeeInfo failed.\n");

    return -1;

}



printf("员工信息为: \n姓名: %s\n年龄: %d\n工号: %d\n", ptEmployeeInfo->szEmployeeName, ptEmployeeInfo->iEmployeeAge, ptEmployeeInfo->iEmployeeNo);



return 0;

}

/**********************************************************************

  • 功能描述:对员工信息字段赋值

  • 输入参数: ptEmployeeInfo: 员工信息结构体

  • 输出参数: ptEmployeeInfo: 员工信息结构体

  • 返回值: 0-成功 -1-失败

  • 其它说明:无

  • 修改日期 版本号 修改人 修改内容


  • 20140617 V1.0 Zhou Zhaoxiong 创建

***********************************************************************/

INT32 GetEmployeeInfo(TEmployeeInfo *ptEmployeeInfo)

{

// 先对输入的指针参数进行异常判断

if (ptEmployeeInfo == NULL)

{

    printf("Input parameter is NULL.\n");

    return -1;

}



strncpy((char *)ptEmployeeInfo->szEmployeeName, "Li Yuanfang", strlen("Li Yuanfang"));   // 对姓名字段赋值

ptEmployeeInfo->iEmployeeAge = 100;       // 对年龄字段赋值

ptEmployeeInfo->iEmployeeNo  = 123456;    // 对工号字段赋值



return 0;     // 赋值成功, 返回0

}

     程序的运行结果如图1所示:

图1 采用指针传递时的程序代码运行结果

    从图1可以看出,函数GetEmployeeInfo的入参为空,不能实现赋值的功能。

三、改进后的采用指针传递时的程序代码
既然程序打印出指针为空的信息,那么我们先对传入的指针进行赋值操作是不是就可以了呢?

    改进后的采用指针传递时的程序代码如下:

/**********************************************************************

  • 版权所有 (C)2014, Zhou Zhaoxiong。

*

  • 文件名称: TestStruct.c

  • 文件标识:无

  • 内容摘要:用于演示结构体变量的用法

  • 其它说明:无

  • 当前版本: V1.0

  • 作 者:周兆熊

  • 完成日期: 20140617

*

  • 修改记录1:// 修改历史记录, 包括修改日期、版本号、修改人及修改内容

  • 修改日期: 20140617

  • 版本号: V1.0

  • 修改人: Zhou Zhaoxiong

  • 修改内容:创建

**********************************************************************/

#include

#include

// 数据类型

typedef signed char INT8;

typedef unsigned char UINT16;

typedef unsigned int UINT32;

typedef signed int INT32;

// 员工信息结构体

typedef struct

{

   INT8    szEmployeeName[100];  // 员工姓名

   UINT16  iEmployeeAge;         // 员工年龄

   UINT32  iEmployeeNo;          // 员工工号

} TEmployeeInfo;

// 函数声明

INT32 GetEmployeeInfo(TEmployeeInfo *ptEmployeeInfo); // 获取员工信息函数

INT32 main(void);

/****************************************************************

  • 功能描述: 主函数

  • 输入参数: 无

  • 输出参数: 无

  • 返回值: 0-执行成功 -1-执行失败

  • 其他说明: 无

  • 修改日期 版本号 修改人 修改内容


  • 20140617 V1.0 Zhou Zhaoxiong 创建

****************************************************************/

INT32 main(void)

{

INT32          iRetValue      = 0;       // 该变量用于表示调用GetEmployeeInfo函数返回的值

TEmployeeInfo *ptEmployeeInfo = NULL;    // 该变量用于存放员工信息



// 先对员工信息字段赋值, 防止空指针的存在

strncpy((char *)ptEmployeeInfo->szEmployeeName, "Di Renjie", strlen("Di Renjie"));   // 对姓名字段赋值

ptEmployeeInfo->iEmployeeAge = 150;       // 对年龄字段赋值

ptEmployeeInfo->iEmployeeNo  = 654321;    // 对工号字段赋值



// 调用函数对员工信息字段赋值, 并打印出来

iRetValue = GetEmployeeInfo(ptEmployeeInfo);

if (iRetValue != 0)

{

    printf("exec GetEmployeeInfo failed.\n");

    return -1;

}



printf("员工信息为: \n姓名: %s\n年龄: %d\n工号: %d\n", ptEmployeeInfo->szEmployeeName, ptEmployeeInfo->iEmployeeAge, ptEmployeeInfo->iEmployeeNo);



return 0;

}

/**********************************************************************

  • 功能描述:对员工信息字段赋值

  • 输入参数: ptEmployeeInfo: 员工信息结构体

  • 输出参数: ptEmployeeInfo: 员工信息结构体

  • 返回值: 0-成功 -1-失败

  • 其它说明:无

  • 修改日期 版本号 修改人 修改内容


  • 20140617 V1.0 Zhou Zhaoxiong 创建

***********************************************************************/

INT32 GetEmployeeInfo(TEmployeeInfo *ptEmployeeInfo)

{

// 先对输入的指针参数进行异常判断

if (ptEmployeeInfo == NULL)

{

    printf("Input parameter is NULL.\n");

    return -1;

}



strncpy((char *)ptEmployeeInfo->szEmployeeName, "Li Yuanfang", strlen("Li Yuanfang"));   // 对姓名字段赋值

ptEmployeeInfo->iEmployeeAge = 100;       // 对年龄字段赋值

ptEmployeeInfo->iEmployeeNo  = 123456;    // 对工号字段赋值



return 0;     // 赋值成功, 返回0

}

      程序的运行结果如图2所示:

图2 改进后的采用指针传递时的程序代码运行结果

   可见,程序出现了内存问题。原因是在传递之前,ptEmployeeInfo指针已经指向了确定的地址,不能让同一个指针同时指向不同的地址。

四、第二次改进后的程序代码
既然不能用指针作为参数进行传递,那么我们就要考虑另外的方法。

    以下代码采用非指针的传递方式:

/**********************************************************************

  • 版权所有 (C)2014, Zhou Zhaoxiong。

*

  • 文件名称: TestStruct.c

  • 文件标识:无

  • 内容摘要:用于演示结构体变量的用法

  • 其它说明:无

  • 当前版本: V1.0

  • 作 者:周兆熊

  • 完成日期: 20140617

*

  • 修改记录1:// 修改历史记录, 包括修改日期、版本号、修改人及修改内容

  • 修改日期: 20140617

  • 版本号: V1.0

  • 修改人: Zhou Zhaoxiong

  • 修改内容:创建

**********************************************************************/

#include

#include

// 数据类型

typedef signed char INT8;

typedef unsigned char UINT16;

typedef unsigned int UINT32;

typedef signed int INT32;

// 员工信息结构体

typedef struct

{

   INT8    szEmployeeName[100];  // 员工姓名

   UINT16  iEmployeeAge;         // 员工年龄

   UINT32  iEmployeeNo;          // 员工工号

} TEmployeeInfo;

// 函数声明

INT32 GetEmployeeInfo(TEmployeeInfo *ptEmployeeInfo); // 获取员工信息函数

INT32 main(void);

/****************************************************************

  • 功能描述: 主函数

  • 输入参数: 无

  • 输出参数: 无

  • 返回值: 0-执行成功 -1-执行失败

  • 其他说明: 无

  • 修改日期 版本号 修改人 修改内容


  • 20140617 V1.0 Zhou Zhaoxiong 创建

****************************************************************/

INT32 main(void)

{

INT32         iRetValue     = 0;      // 该变量用于表示调用GetEmployeeInfo函数返回的值

TEmployeeInfo tEmployeeInfo = {0};    // 该变量用于存放员工信息



// 调用函数对员工信息字段赋值, 并打印出来

iRetValue = GetEmployeeInfo(&tEmployeeInfo);

if (iRetValue != 0)

{

    printf("exec GetEmployeeInfo failed.\n");

    return -1;

}



printf("员工信息为: \n姓名: %s\n年龄: %d\n工号: %d\n", tEmployeeInfo.szEmployeeName, tEmployeeInfo.iEmployeeAge, tEmployeeInfo.iEmployeeNo);



return 0;

}

/**********************************************************************

  • 功能描述:对员工信息字段赋值

  • 输入参数: ptEmployeeInfo: 员工信息结构体

  • 输出参数: ptEmployeeInfo: 员工信息结构体

  • 返回值: 0-成功 -1-失败

  • 其它说明:无

  • 修改日期 版本号 修改人 修改内容


  • 20140617 V1.0 Zhou Zhaoxiong 创建

***********************************************************************/

INT32 GetEmployeeInfo(TEmployeeInfo *ptEmployeeInfo)

{

// 先对输入的指针参数进行异常判断

if (ptEmployeeInfo == NULL)

{

    printf("Input parameter is NULL.\n");

    return -1;

}



strncpy((char *)ptEmployeeInfo->szEmployeeName, "Li Yuanfang", strlen("Li Yuanfang"));   // 对姓名字段赋值

ptEmployeeInfo->iEmployeeAge = 100;       // 对年龄字段赋值

ptEmployeeInfo->iEmployeeNo  = 123456;    // 对工号字段赋值



return 0;     // 赋值成功, 返回0

}

    程序的执行结果如图3所示:

图3第二次改进后的程序代码执行结果

    从图3可以看出,程序执行结果正确,得到了我们想要的结果。

五、总结
在编写代码的过程中,我们需要注意以下方面:

   (1) 程序头部、函数头部及重要的程序语句处一定要有注释,这体现了软件开发人员的专业素养。

   (2) 函数中出现的变量在定义的同时要进行初始化,函数在调用之前一定要先进行声明。

   (3) 对于函数中的指针变量参数,在使用之前一定要先进行异常判断(即判断其是否为NULL)。

   (4) 对于有返回值的函数,要用不同的返回值来区别不同的执行结果,并在重要的地方打印出提示信息,方便对代码的调试。



    指针是C语言的精华所在,同时也是难点所在。对于一个合格的软件开发工程师来说,一定要熟练掌握指针的使用方法。

C语言 结构体作为函数的参数
1)使用结构体变量作为函数的参数

  使用结构体变量作为函数的实参时,采用的是值传递,会将结构体变量所占内存单元的内容全部顺序传递给形参,形参必须是同类型的结构体变量

demo:

复制代码
1 # include
2 # include
3
4 //创建一个Student结构
5 struct Student
6 {
7 char name[30];
8 float fScore[3];
9 }student={"dire",98.5,89.0,93.5}; //初始化结构体变量
10
11 void Display(struct Student su) //形参为同类型的结构体(Student结构)
12 {
13 printf("-----Information------\n");
14 printf("Name:%s",su.name);
15 printf("Chinese:%.2f\n",su.fScore[0]);
16 printf("Math:%.2f\n",su.fScore[1]);
17 printf("English:%.2f",su.fScore[2]);
18 printf("平均分数为:%.2f\n",(su.fScore[0]+su.fScore[1],su.fScore[2])/3);
19 }
20
21 int main ()
22 {
23

24 Display(student);
25

26 return 0;
27 }
复制代码
Printf:

2)使用指向结构体变量的指针作为函数参数

Demo:

复制代码
1 # include
2 # include
3
4 struct Student {
5 char name[20];
6 float fScore[3];
7 }student = {"dire",98.5,89.0,93.5}; //初始化结构体变量
8
9
10 void Display(struct Student *pStruct)
11 {
12 printf("------Information-------\n");
13 printf("Name:%s\n",pStruct->name);
14 printf("Chinese:%.2f\n",(*pStruct).fScore[0]);
15 printf("Math:%.2f\n",(*pStruct).fScore[1]);
16 printf("English:%.2f\n",pStruct->fScore[2]);
17 }
18
19
20 int main ()
21 {
22 Display(&student); //将结构体变量的首地址作为实参传入pStruct指针变量中
23

24 return 0;
25 }
复制代码
3)使用结构体变量的成员作为函数参数

  这种方式为函数传递参数与普通的变量作为实参是一样的,是值传递

C语言用结构体指针作函数参数

这种方式比用结构体变量作函数参数效率高,因为无需传递各个成员的值,只需传递一个地址,且函数中的结构体成员并不占据新的内存单元,而与主调函数中的成员共享存储单元。这种方式还可通过修改形参所指成员影响实参所对应的成员值。
例如

struct book
{
char bookname[30];
int quantity;
};
main()
{
void fun(struct book*p);
struct book book1={"Programming in C",10};
fun(&book1);
printf("%d copies\n", book1.quantity);
}
void fun(struct book*p)
{
printf("The book \" %s\" has ",p->bookname);
p->quantity -=3;
}

显示:The book "Programming in C" has 7 copies
此外,还可将结构体数组作为函数参数;还可设计结构体指针型函数,即返回的地址是指向结构体类型数据的。

struct dangdangtest
{

char name[30];

int num;

};

void change(int num)//值传递 新建一个变量接受传递的值
{
num = 1000;
}

//使用结构体作为参数 浪费内存 需要建立结构体
void change2(struct dangdangtest ddt)
{
ddt.num = 1000;
printf("\nmain=%p,%p",ddt,&ddt.num);//函数内部结构体地址
}
//函数内部改变需要地址 所以需要指针保存
void changeall(struct dangdangtest *p)

{
(*p).num = 1000;//*根据地址取出内容
}
void main5()
{
struct dangdangtest ddt;
ddt.num = 99;
sprintf(ddt.name,"adf");//初始化
printf("\nmain=%p,%p",ddt,&ddt.num);//main函数内部结构体地址
/*change(ddt.num);
printf("%d",ddt.num);99*/

/*change2(ddt);
printf("%d",ddt.num);*/
changeall(&ddt);
printf("\n%d",ddt.num);
getchar();

}

//参数对于数组来说传递的是地址 4个字节
void datatest(struct dangdangtest ddd[10])
{
printf("datatest=%d",sizeof(ddd));
}

void dtc(struct dangdangtest ddd[10])
{
ddd[4].num = 88;
sprintf(ddd[4].name,"654656");//前面有提过
printf("datatest=%d",sizeof(ddd));
}
void main()
{
struct dangdangtest ddd[10];//10个元素 36*10

struct dangdangtest *p = ddd;
printf("\n%d",sizeof(ddd));//
 ddd[0].num = 90;
sprintf(ddd[0].name,"dfasdf");
/*datatest(ddd);
printf("main=%d",sizeof(ddd));*/
getchar();

}

struct book
{
char bookname[30];
int quantity;
};
main()
{
void fun(struct book*p);
struct book book1={"Programming in C",10};
fun(&book1);
printf("%d copies\n", book1.quantity);
}
void fun(struct book*p)
{
printf("The book \" %s\" has ",p->bookname);
p->quantity -=3;
}