C语言提供了另外两种构造类型:结构体与公用体,用来存储若干个类型不同但彼此组成一个集合的数据总体。

(1)结构体类型与结构体变量

1.定义

其一般形式为:

struct  结构体类型名{

数据类型1 成员名1;

数据类型2 成员名2;

数据类型3 成员名3;

......

}

定义一个结构体变量只是描述结构体的组织形式,并不意味着将分配一段内存单元来存放个数据项成员。它的作用只是告诉编译系统所定义的结构体类型是有哪些类型的成员构成的,各占多少字节,按什么形式存储,并把他们当作一个整体来处理。

2.结构体变量的定义:

结构体类型的变量的定义有三种方法:

1)先定义结构体类型,再定义结构体变量;struct student{省略成员的定义};struct student stu1,stu2;

2)定义结构体类型的同时,定义结构体变量;struct student{省略成员的定义}stu1,stu2;

3)不定义结构体的类型,直接定义变量。(此时结构体是无名的)struct{省略成员的定义}stu1,stu2;

结构体成员也可以是一个结构体变量,即一个结构体的定义中可以嵌套另外一个结构体的结构体的结构体。

struct date{

  int year;

int month;

int day;

};

struct student{

long int number;

char name[20];

char sex;

struct date birthday;

char addr[30];

};

3.结构体变量的引用

在定义结构体类型变量以后,就可以引用结构体类型变量,如赋值,存取和运算等。遵循以下规则:

1)不能将结构体变量当作一个整体处理;

2)访问带有结构体变量成员的结构体时应采取逐级访问的方式;

3)结构体的成员变量和普通变量一样可以进行各种运算。

4.结构体变量的初始化

结构体类型是数组类型的扩充,只是它的成员项可以具有不同的数据类型:

struct student{

long num;

char name[20];

char sex;

char addr[20];

}s1={2006001,"MenAngel",'m',"anhui hefei"};

(2)结构体数组

结构体数组与普通的变量的数组大致相同:

初始化:

struct student{}stu1={{括号里与单个结构体初始化方式相同},{},{}......};

1)输入3名学生的信息并输出

 #include<stdio.h>
#include<string.h> struct student{
long num;
char name[];
int age;
char sex;
int score;
}; int main(){
struct student stu[];
int i;
printf("学生的数据是:长整型的学号,字符数组的名字,整型的年龄,字符型的性别,整型的分数。\n");
for(i=;i<;i++){
printf("Please input all data of student[%d]\n",i+);
scanf("%ld,%s%d,%c,%d",&stu[i].num,&stu[i].name,&stu[i].age,&stu[i].sex,&stu[i].score);
}
printf("\n num\t name\t age\t sex\t score\n");
for(i=;i<;i++){
printf("%ld\t%s\t%d\t%4c\t%5d\n",stu[i].num,stu[i].name,stu[i].age,stu[i].sex,stu[i].score);
}
return ;
}

本例用是scanf函数输入各成员时,除字符型数组外,其他变量都采用","分隔,而字符数组以回车作为输入的结束。

2)统计候选人得票数。假设有3名候选人,每次输入一个得票人的名字,要求最后输出每个人的得票总数。

 #include<stdio.h>
#include<string.h> struct person
{
char name[];
int count;
} leader[]={"Hu",,"Li",,"Ma",};//结构体数组的赋值 int main(){
int i,j;
char leader_name[];
for(i=;i<=;i++){
scanf("%s",leader_name);
for(j=;j<;j++){
if(strcmp(leader_name ,leader[j].name )==){
leader[j].count++;
}
}
}
for(i=;i<;i++){
printf("%5s:%d\n",leader[i].name,leader[i].count);
}
return ;
}

(3)结构体指针

指向结构体的指针称为结构体指针变量。该变量存放结构体变量的起始地址。结构体指针变量也可以指向结构体数组中的元素。

1.结构体指针变量的定义

struct 结构体类型 *结构体指针

例如:

struct student stu1,*p=&stu1;

在访问结构体变量的成员时:p->num等价于(*p).num;

2.结构体数组指针

一个结构体指针变量可以指向结构体数组,即将结构体数组的起始地址赋给指针变量,这种指针就是结构体指针。

struct student stu1[10],*p=stu1;

(4)结构体类型数据在函数间的传递

函数间不仅可以传递简单变量、数组、指针这些类型的数据,还可以传递结构体类型的数据。函数间结构体类型数据的传递和普通变量一样,可以“按值传递”,也可以“按地址传递”。

1.结构体变量作为函数参数

用结构体变量作为函数实参传递数据:

 #include<stdio.h>

 struct Teacher{
char name[];
float salary;
float reword;
float income;
};
void display(struct Teacher p)
{
printf("\n%s %7.2f %7.2f %7.2f",p.name,p.salary,p.reword,p.income);
p.salary=;
p.reword=;
p.income=p.salary+p.reword;
printf("\n%s %7.2f %7.2f %7.2f",p.name,p.salary,p.reword,p.income);
}
int main(){
struct Teacher teacher;
printf("\nInput name:");
scanf("%s",teacher.name);
teacher.salary=;
teacher.reword=;
teacher.income=teacher.salary+teacher.reword;
display(teacher);
printf("\n%s %7.2f %7.2f %7.2f",teacher.name,teacher.salary,teacher.reword,teacher.income);

调用函数的实参与被调用函数的形参都是结构体变量名。

形参和实参的结构体类型相同,但运行时分配在不同的存储空间,因此,被调用函数不能修改调用函数的值。

2.结构体指针变量作为函数参数

 #include<stdio.h>

 struct student{
long num;
char name[];
float score[];
}stb1={,"LiYing",67.9,78.5,91.2},stb2={,"YangLi",87.9,97.6,90.0}; void output(struct student *p){
printf("%ld\n%s\n%f\n%f\n%f\n",p->num,p->name,p->score[],p->score[],p->score[]);
printf("\n");
}; int main(){
output(&stb1);
output(&stb2);
return ;
}

3.结构体数组作为函数参数

用结构体数组写一个联系人管理的c程序,包括增删改查,打印所有联系人信息五个功能!

 #include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct contacter{
int num;
char name[];
unsigned long linknumber;
};
struct contacter linkers[];
int count=;
//程序开始时的提醒:
void FirstWarn(){
printf("This is a c program used to manange your address book:\n");
printf("Chose different choice,then you will get disfferent function:\n");
printf("1.Establish and save a new contacter:\n");
printf("2.Delete a contacter:\n");
printf("3.Modify a contacter:\n");
printf("4.Search information of a contacter:\n");
printf("5.Print all of your contacters:\n");
}
//第1个功能,用来新建一个联系人
void newContacters(){
getchar();
if(count==){
printf("There is no storage space any more!\n");
}else if(count>=&&count<){
printf("Please input name:\n");
gets(linkers[count].name);
printf("please input his or her telephone number:\n");
scanf("%ld",&linkers[count].linknumber);
linkers[count].num=+count;
count++;
}
}
//用来验证输入的命令数字
void validate(int* p){
if(*p<|*p>){
printf("Warning: No Such order!\n");
printf("Please input a new order again:\n");
scanf("%d",p);
validate(p);
}
}
//第2个功能,实现删除一个联系人
//(1)用号码来删除
void deleteByNumber(int num){
int n;
n=num-;
for(int i=n;i<count;i++){
strcpy(linkers[i].name,linkers[i+].name);
linkers[i].linknumber=linkers[i+].linknumber;
}
count--;
}
//(2)用名字来删除
void deleteByName(char name[]){
for(int i=;i<count;i++)
if(!strcmp(name,linkers[i].name))
deleteByNumber(+i);
}
//第3个功能,实现输入名称修改联系人的信息
void modifyByName(char *name){
for(int i=;i<count;i++){
if(!strcmp(name,linkers[i].name)){
printf("Please input this linker's telephone:\n");
scanf("%d",&linkers[i].linknumber);
}
printf("After modifing:num=%d name=%s telephone=%ld\n",
linkers[i].num,linkers[i].name,linkers[i].linknumber);
}
}
void modifyByNumber(int num){
printf("Please input this linker's name\n");
gets(linkers[num-].name);
printf("Please input this linkers' telephone\n");
scanf("%ld",&linkers[num-].linknumber);
printf("After modifing:num=%d name=%s telephone=%ld\n",
linkers[num-].num,linkers[num-].name,linkers[num-].linknumber);
}
//第4个功能,实现查询功能
int searchByName(char *name,struct contacter *p,int count){
for(int i=;i<count;i++){
if(!strcmp(name,p[i].name)){
printf("The information of this person:\n");
printf("num=%d,name=%15s,telephone=%ld\n",p[i].num,p[i].name,p[i].linknumber);
return ;
}
}
return ;
}
int searchByNumber(int num,struct contacter *p, int count){
if(<=num-&&num-<=count){
printf("num=%d,name=%15s,telephone=%ld\n",
p[num-].num,p[num-].name,p[num-].linknumber);
}
}
//第5个功能,实现打印信息
void printAll(){
for(int i=;i<count;i++){
printf("第%d位联系人:num=%d; name=%15s; telephone=%ld \n",i+,linkers[i].num,linkers[i].name,linkers[i].linknumber);
}
}
int main(){
//在启动程序时自动创建一个包含100个变量的结构体数组
//记录用户的选择
int choice;
FirstWarn();
while(){
printf("Please input a order:\n");
scanf("%d",&choice);
validate(&choice);
switch(choice){
case :{
newContacters();
break;
}
case :{
printf("Chose the way of deleting linkers:\n");
printf("0.By name\n");
printf("1.By Number:\n");
int temp;
scanf("%d",&temp);
if(temp){
int number;
printf("Input the number:\n");
scanf("%d",&number);
deleteByNumber(number);
}else{
char name[];
printf("Print the name of linker who you want to delete:\n");
scanf("%s",name);
deleteByName(name);
}
break;
}
case :{
int list=;
printf("Chose a way to modyfy the contacter:\n");
printf("1.Modify the telephone only(By name)!\n");
printf("0.Modify both name and telephone(By number)!\n");
scanf("%d",&list);
if(list){
char name[];
printf("Please input the name:\n");
getchar();
gets(name);
modifyByName(name);
}else{
int num;
printf("Please input the number:\n");
scanf("%d",&num);
getchar();
modifyByNumber(num);
}
break;
}
case : {
int list=;
printf("Chose a way to search the contacter:\n");
printf("1.search by name!\n");
printf("0.search by number!\n");
scanf("%d",&list);
if(list){
char name[];
printf("Please input the name:\n");
scanf("%s",name);
if(!searchByName(name,linkers,count)){
printf("no such man!");
}
}else{
int num;
printf("Please input the person's number you want to search:\n");
scanf("%d",&num);
searchByNumber(num,linkers,count);
}
break;
}
case : {printAll();
break;}
default:printf("Errors!");break;
}
}
}

由于屏幕小,测试功能的截屏就是以上那么多!

总结遇到的问题:

1.在从键盘输入数据用scanf("%d",n),忘了加&,然而也不报错,检查半天,痛心!应为scanf("%d",&n);

2.本例用记录数组大小的数count,和结构体数组作为全局变量,事实上这样在每个函数中都可以自由更改它们的值。如果使用值传递的方式是不能更改count的值的,也不能更改结构体数组的值,操作起来非常不方便。

3.在用gets()函数,或者scanf()函数接收字符串时一定要确定前面是否有scanf()函数,如果有,确定用getchar();接收上面输入过程产生的回车符。

4.本例用long型数据存储电话号码,但貌似只能有8位整数,unsigned long貌似只能输入9位,无法达到11位的要求。这里就不在详细追究。事实上可以用字符数组来接收电话号码。

c的详细学习(9)结构体与共用体的学习(一)的更多相关文章

  1. 不可或缺 Windows Native (8) - C 语言: 结构体,共用体,枚举,类型定义符

    [源码下载] 不可或缺 Windows Native (8) - C 语言: 结构体,共用体,枚举,类型定义符 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 结构体 ...

  2. C++程序设计之结构体,共用体,枚举和typedef

    [1]结构体的基本功 注意结构体里面可以有很多东西,可以结构体里面包含结构体 #include<iostream> using namespace std; struct Date { i ...

  3. 全国计算机等级考试二级教程-C语言程序设计_第14章_结构体、共用体和用户定义类型

    函数的返回值是结构体类型 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> struct ...

  4. __c语言__结构体、共用体、枚举__笔记

    2017-09-16 21:14:09 结构体,共用体,枚举 1.结构体 把不同的类型整合成一个有机的整体,以便于引用,这个类型就叫做结构体 1)结构体变量的定义方式(3种)和引用成员变量: 定义一个 ...

  5. C++面试常见问题——13结构体与共用体的sizeof

    结构体与共用体的sizeof 结构体的sizeof 结构体变量占用的内存空间大小通常是其基本类型的大小,但是由例外(字节对齐机制) struct S1{ char c[5]; int a; doubl ...

  6. C语言程序设计(十二) 结构体和共用体

    第十二章 结构体和共用体 当需要表示复杂对象时,仅使用几个基本数据类型显然是不够的 根本的解决方法是允许用户自定义数据类型 构造数据类型(复合数据类型)允许用户根据实际需要利用已有的基本数据类型来构造 ...

  7. C语言------结构体和共用体

    仅供借鉴.仅供借鉴.仅供借鉴(整理了一下大一C语言每个章节的练习题.没得题目.只有程序了) 文章目录 1 .实训名称 2 .实训目的及要求 3.源代码及运行截图 4 .小结 1 .实训名称 实训8:结 ...

  8. c的详细学习(10)结构体与共用体的学习(二)

    在c语言中,结构体数据类型与共用体数据类型都属于构造类型.共用体与结构体数据类型在定义上十分相似,但它们在存储空间的占用分配上有本质的区别.结构体变量是各种类型数据的集合,各成员占据不同的存储空间,而 ...

  9. ndk学习之C语言基础复习----结构体、共用体与C++开端

    自己实现sprintf功能: 关于C中的系统函数sprintf在上次[https://www.cnblogs.com/webor2006/p/7545627.html]学习中已经用到过了,这里再来回顾 ...

随机推荐

  1. CentOS6.8 编译安装LNMP

    思路:根据Linux系统以及公司网站系统的信息,选择合适的安装包进行安装 一.查看系统信息 # uname -a # 查看内核/操作系统/CPU信息 # /etc/issue # 查看操作系统版本 # ...

  2. Asp.Mvc将生成的视图保存为字符串

    public static class ViewExtensions { /// <summary> /// 在控制器内获取指定视图生成后的HTML /// </summary> ...

  3. 开发中可能会用到的几个小tip----QT, pycharm, android, 等

    QT: 如果是在windows下开发的话,添加外部库,外部包含头文件路径的时候,要注意用相对路径,或者在项目上右键添加外部库的路径或者头文件路径,否则,会卡在这里开始怀疑人生... 如果是在linux ...

  4. Keepalived + MySQLfailover + GTIDs 高可用

    架构图     10.1.1.207    mysql master + keepalived     10.1.1.206    mysql slave ( backup master ) + ke ...

  5. 【问题记录】springmvc国际化问题

    异常-Cannot change HTTP accept header - use a different locale resolution strategy springmvc国际化时,local ...

  6. 《Lucene in Action 第二版》第4章节 学习总结 -- Lucene中的分析

    通过第四章的学习,可以了解lucene的分析过程是怎样的,并且可以学会如何使用lucene内置分析器,以及自定义分析器.下面是具体总结 1. 分析(Analysis)是什么? 在lucene中,分析就 ...

  7. Linux中openmpi配置

    到 http://www.open-mpi.org/ 下载openmpi并解压,事先安装gcc或g++. 我是openmpi-1.6.5,进入解压文件夹,执行 ./configure 这一步执行时间会 ...

  8. erlang实现一个进程池 pool

    erlang的实现一个简单的进程池. erlang进程是非常轻量级的,这个进程池的主要目的是用一种通用的方式去管理和限制系统中运行的资源占用.当运行的工作者进程数量达到上限,进程池还可以把任务放到队列 ...

  9. [转]基于fiddler的APP抓包及服务端模拟

    在HTTP接口的测试过程中,一般我们会按照如下的步骤进行: 1)测试环境的准备 2)HTTP消息体的构造 3)HTTP消息的发送及断言 如果我们可以拿到项目组的接口文档,并且HTTP后台服务是可以工作 ...

  10. 嵌入式开发之davinci--- 8148/8168/8127 中的大屏分布式拼接显示系统

    其实在接触从12年接触8127系列ipnc 时看到200w和500w的高清像素,我就萌生了视频拼接的兴趣,没想到今年的安博会就有公司推出产品了,它就是上海的环视科技,从他的主页可以看到,明显的有个只能 ...