C语言数据类型(2)——构造数据类型

前面一文中已经讲过C语言数据类型分为三种:基本数据类型、构造数据类型、指针类型。
基本数据类型上文中已经说明,本文介绍构造数据类型。构造数据类型又分为三种:数组类型、结构体类型、共用体类型、枚举类型。
在这里插入图片描述

数组类型

首先我们需要明确一个问题,为什么要有数组?
例如:现在需要统计10个学生的成绩,若用基本数据类型来定义的至少需要定义10个变量在存储这些数据,如果是100个学生就至少需要100个变量。

float a0,a1,a2,a3,a4,a5,a6,a7,a8,a9;

使用基本数据类型在定义变量时如果同一类型变量的个数较多,那么在定义时会比较麻烦。如果用数组来解决上述问题,那么就会很方便,

float a[10];

只需要一个语句就可以实现多个同一类型变量的定义,相比之下数组的优势就凸显出来,这就是我们为什么需要数组。有了这个实际问题后我们也更容易理解数组的概念——一组相同类型的数据的集合。
数组和数组元素:数组是用一个名字表示的一组相同类型的数据的集合,这个名字就称为数组名。数组中的数据分别存储在用下标区分的变量中,这些变量称为下标变量或数组元素。每个下标变量相当于一个简单变量,数组的类型也就是该数组的下标变量的数据类型。数组属于构造类型,构造类型的数据是由基本类型数据按一定规则构成的。
C语言中使用的数组包括一维数组和多维数组。

一维数组

一维数组定义

定义形式:
数据类型 数组名[常量表达式];

“数据类型”: 是数组元素的数据类型。
“数组名”: 遵循C语言标识符规则。
“常量表达式”:表示数组中有多少个元素,即数组的长度。它可以是整型常量、整型常量表达式或符号常量。

int a[5];

定义了一个一维数组a,int表示数组中a中的每一个元素都是整型的,数组名为a,此数组有5个元素。数组下标从0开始,因此上面定义a数组的6个元素是a[0]、a[1]、a[2]、a[3]、a[4],它们在内存中连续存放,数组的首地址就是a[0]的地址,数组名代表数组的首地址(地址这点很重要,在指针中会用到),即a的值与a[0]的地址值(&a[0])一样。

一维数组引用

引用形式:
数组名[下标表达式 ];

其中“下标表达式”:只能是整型常量或整型表达式。
注意:下标从0开始(下界为0),数组的最大下标(上界)是数组长度减1。

	int a[10];
	a[0]=0;
	scanf("%d",&a[10]);/*下标越界*/

如上代码第三行为错误用法,数组下标只能到(n-1)位,n为数组元素个数。

一维数组初始化

1.在定义数组时。对全部数组元素赋初值

int a[5]={
    
    0,1,2,3,4};

a[0]的值为0,a[1]的值为1,···,a[4]的值为4
对全部数组元素赋初值时可以不同指定数组长度,如:

int a[]={
    
    0,1,2,3,4};

系统会根据初值的个数定义a数组长度为5。
2.在定义数组时,对部分数组元素赋初值

int a[5]={
    
    0,1,2};

a[0]的值为0,a[1]的值为1,a[2]的值为2,其余元素为0。

二维数组

二维数组定义

定义形式:
数据类型 数组名[常量表达式1][常量表达式2];

[常量表达式1]表示二维数组的行数,[常量表达式2]表示二维数组的列数。

float x[2][3];

定义x为2行3列数组,共六个元素,每一个元素都是float类型。系统为二维数组在内存中分配了一连续的存储空间,元素的排列顺序是按行存放的,即x[0][0]、x[0][1]、x[0][2]、x[1][0]、x[1][1]、x[1][2]。数组名代表数组首地址。
二维数组可看作是一种特殊的一维数组,可以把x数组看作是包含二个大元素的一维数组,每个元素又是一个含有三个元素的一维数组。
x[0]------x[0][0]、x[0][1]、x[0][2]
x[1]------x[1][0]、x[1][1]、x[1][2]
x[0]是二维数组第一行的首地址,即x[0][0]的地址,x[1]是二维数组第二行的首地址,即x[1][0]的地址。

二维数组的引用

引用形式:
数组名[行下标表达式][列下标表达式]
注意:二维数组的行、列下标均从0开始(下界为0)

int a[3][4];
a[0][0]=3;
a[0][1]=a[0][0]+10;	

错误引用:

a[3][4]=3;/*下标越界*/
a[1,2]=1;/*应写成a[1][2]=1;*/

二维数组初始化

1.按行赋初值:

int a[2][3]={
    
    {
    
    1,2,3},{
    
    4,5,6}};

初始化结果:
第一行:1 2 3
第二行:4 5 6
2.按数组元素在内存中排列的顺序对各元素赋初值:

int a[2][3]={
    
    1,2,3,4,5,6};

初始化结果:
第一行:1 2 3
第二行:4 5 6
3.给部分元素赋初值:

int a[2][3]={
    
    {
    
    1},{
    
    4}};

初始化结果:
第一行:1 0 0
第二行:4 0 0

特殊注意——字符数组

同前面整型数组、实型数组类似,字符数组也是一种数组的类型。那为什么要把字符数组单独提出来说呢?它不同于其他类型的数组,若是整型数组那么其中存放的就是整型数据,若是实型数组那么其中存放的就是实型数据。但字符型数组中既可以存放字符数据又可以存放字符串,且字符串只能存放于字符数组中,这就是它的特殊之处。

字符串

要搞清楚字符数组中到底存放的字符数据还是字符串,首先要搞清楚的是字符与字符串的区别。字符与字符串的区别就是是否有字符串结束标志(‘\0’)。 若有字符串结束标志就是字符串,反正则是字符。

char a[5]={
    
    'C','h', 'i', 'n', 'a' };
char b[6]={
    
    'C','h', 'i', 'n', 'a' , '\0'};

如上两行代码所示,a数组中无字符串结束标志(‘\0’),所以a数组中存放的是字符,其分别为’C’、‘h’、‘i’、‘n’、‘a’;而在b数组中含有’\0’,b数组中存放的就是字符串China。

字符数组的初始化

1.用字符常量赋初值

char a[5]={
    
    'C','h', 'i', 'n', 'a' };

a数组中存放的是5个字符型数据,不是字符串,各数组元素元素与下标对应类似整型数组。

char b[6]={
    
    'C','h', 'i', 'n', 'a' , '\0'};

因b数组中 b[5]=‘\0’,所以b数组中存放的是字符串。

2.用字符串常量赋初值

char str[10]= {
    
    "a string"};
char str[10]= "a string";

上述两行代码功能相同,都是在str数组中存放字符串(a string)。

char a[3][10]={
    
    "basic","pascal","c"};

a数组有三行,每一行存放一个字符串。
这也说明了若数组长度大于所赋值的内容长度时,系统会自动在后面剩余位置中补’\0’,这时数组中所存放的内容就会变为字符串。如:

char s3[7]={
    
     's', 't', 'r', 'i', 'n', 'g'};

字符数组长度为7位,而赋值时用户只赋了6位,这时系统就会自动将第七位补’\0’,即s3[7]=‘\0’

3.初始化时长度的省略

char s1[ ]= "Good morning!";

此时s1数组的长度为14,s1[13]=‘\0’。s1数组中存放的是一个字符串。

char s2[ ]={
    
     's', 't', 'r', 'i', 'n', 'g'};

此时s2数组的长度为6。数组中无字符串结束标志。因此不能作为字符串使用。

字符数组的引用

字符数组的引用可分为对字符数组单个元素的引用和对字符数组整体的引用。对字符数组单个元素的引用与整型数组和实型数组相同。对字符数组的整体引用主要表现在输入和输出上。

char c[ ]= "China";
printf("%s",c);

其中c是数组名,代表数组的首地址。输出结果为China。

char c[10];
scanf("%s",c)

若输入为Beijing,则数组中存放的是字符串"Beijing".

数组总结

数组是表示一组相同类型的数据的集合,在需要很多相同类型变量时被使用。分为一维数组和多维数组。
首先需要注意的点就是数组的下标不能越界,数组的下标是从0开始的,在定义或引用时不能下标越界,这是很多时候容易犯的错误。
第二点就是数组的地址问题,地址问题在后面指针的引用中是很重要的,要明确数组名代表数组的首地址以及二维数组各行首地址是什么。数组的元素在计算机中地址是如何分配的,这对后续学习指针是有帮助的。

结构体类型

数组类型对于大批量数据处理十分方便和灵活,但也有一定的限制,即同一数组的元素必须都是同一类型的数据。有没有一种可以将各种数据类型集合到一起的数据类型呢?这时就有了结构体和共用体。
结构体由若干数据项组成,组成结构体的各个数据项被称为结构体成员。结构体中各成员的数据类型可以不同。在使用结构体类型数据之前,必须先对结构体类型进行定义。结构体定义的一般形式:

struct 结构体名
{
    
    数据类型1 成员名1;
 数据类型2 成员名2...
 数据类型n 成员名n;
};

其中struct是C语言的关键字,它表明进行结构体类型的定义。最后分号表示结构体类型定义的结束。结构体成员可以是C语言所允许的任何数据类型。例如:

struct bookcard
{
    
    char num[10];
 char mane[30];
 char author[30];
 char publisher[60];
 float price;
 int n;
};

注:结构体类型的定义只说明了该类型的构成形式,系统并不为其分配内存空间,编译系统仅给变量分配内存空间,故结构体所占的空间等于各结构体成员所占空间之和。结构体成员的类型也可以是另一结构体类型。

结构体类型变量的定义

1.利用已定义的结构体类型定义变量
当一个程序中多个函数内部需要定义同一结构体类型的变量时应采用此方法,而且结构体类型应定义为全局类型,形式为
struct 结构体名 变量名表;

struct student
{
    
    char num[8];name[20];sex;
 int age;
 float score;
};
void main()
{
    
    struct student a;
...
}
f1()
{
    
    struct student b;
...
}

由于struct student类型定义在函数之外,所以它为全局变量,因此可在main函数,f1函数中用它定义结构体变量a、b。
2.在定义结构体类型的同时定义变量
此方法一般用于定义外部变量,同时此结构体类型名还可以在各个函数中用于定义局部变量。形式为:
struct 结构体名
{成员定义表;
}变量名表;

struct student
{
    
    char num[8];name[20];sex;
 int age;
 float score;
}st[30];
void main()
{
    
    struct student s;
...
}
f1()
{
    
    struct student x;
...
}

单一的struct student类型变量只能描述一个学生的信息,如果需要保存30个学生的信息时则可以定义一个结构体类型数组。如上所示,在定义全局类型名的同时定义了一个外部的结构体数组,定义方法与其他类型数组定义相同。此数组中每个元素均为结构体类型变量。 这两种构造类型的结合使用,使其对数据的处理更具有普遍性。

3.直接定义结构体类型变量
在程序中仅有一处需要某种结构体类型变量时,可用此方法。在此方法中没有具体的指出结构体类型名,形式为:
struct
{成员定义表;
}变量名表;

void main()
{
    
    struct
 {
    
    char num[8],name[30],sex;
  int age;
  float score;
 }st[30],a,b,c;
 int i,j;
 ...
}

结构体变量的初始化

在定义结构体变量的同时也可以对其成员赋初值。初值表用“{}”括起来,表中个数据以逗号分隔,并且应与结构体类型定义时的成员个数相同,类型一致。如果初值个数少于结构体成员个数,则将无初值对于的成员赋以0值。如果初值个数多于结构体成员个数时,则编译出错。
例:结构体变量初始化:

struct date
{
    
    int year,month,day;};
struct student
{
    
    char num[8],name[30],sex;
 struct date birthday;
 float score;
}a={
    
    "40826011","Li ming","M",{
    
    1991,2,9},87.5},
 b={
    
    "40826025","Zhang qiang","F",{
    
    1990,5,12},85},c,d;

结构体数组的初始化:

struct s
{
    
    char num[8],name[30],sex;
 float score;
}stu[3]={
    
    
		{
    
    "40826011","Li ming","M",87.5},
		{
    
    "40826025","Zhang qiang","F",85},
		{
    
    "40826032","Wang xinping","F",90}
		};

结构体变量成员的引用形式

引用结构体变量成员的一般形式为:
结构体变量名.成员名
其中“.”是分量运算符,运算级别最高。例如在结构体变量初始化中的第一段代码中a的个成员可以表示为a.num、a.name、a.sex、a.birthday和a.score。a,b,c,d是同一类型变量,对各自的同名成员num可以用a.num,b.num,c.num和d.num来区分。
结构体指针: struct student *p;
例如:

struct code
{
    
    int n;
 char c;
}a,*p=&a;

p是指向a的结构体指针,对于变量a中的成员有3种引用方式:
1.a.n,a.c通过变量名进行分量运算选择成员;
2.(*p).n,(*p).c:利用指针变量间接存储运算符访问目标变量;
3.p->n,p->c:这是专门用于结构体指针变量引用结构体成员的一种形式,它等价于第二种形式。

共用体类型

共用体类似是一种将不同数据类型共享存储结构的构造类型,即共用体变量的所有成员将占用同一存储空间。这也说明了共用体所占的空间等于它的成员中所占的最大空间。运用此种类型数据的优点是节省存储空间。
共用体类型定义的一般形式为:

union 共用体名
{
    
    数据类型1 成员名1;
 数据类型2 成员名2...
 数据类型n 成员名n;
 }

其中union是C语言的关键字,它表明进行共用体类型的定义。最后分号表示共用体类型定义的结束。共用体成员可以是C语言所允许的任何数据类型。例如:

union utype
{
    
    int i;
 char ch;
 long l;
 char c[4];
};

共用体变量的定义

共用体类型变量定义的形式与结构体变量定义相似。
1.union 共用体名 变量名表;
2.union 共用体名
{成员定义表;
}变量名表;

3.union
{成员定义表;
}变量名表;

共用体变量成员的引用

与结构体变量类型,共用体成员的引用也有3种形式

union u
{
    
    char u1;
 int u2;
}x,*p=&x;

引用形式为:
1.x.u1,x.u2;
2.(*p).u1,(*p).u2;
3.p->u1,p->u2;

猜你喜欢

转载自blog.csdn.net/Tao_9/article/details/129711370
今日推荐