前面我们介绍了基本的数据类型 在c语言中 有一种特殊的数据类型 由程序员来定义类型
目录
一结构体
1.1概述
:结构是 C 编程中另一种用户自定义的可用的数据类型,它允许您存储不同类型的数据项
1.2定义结构体
结构体定义由关键字 struct 和结构体名组成,结构体名可以根据需要自行定义。
struct 语句定义了一个包含多个成员的新的数据类型,struct 语句的格式如下
struct tag {
member-list
member-list
member-list
...
} variable-list ;
tag 是结构体标签。
member-list 是标准的变量定义,比如 int i; 或者 float f;,或者其他有效的变量定义。
variable-list 结构变量,定义在结构的末尾,最后一个分号之前,您可以指定一个或多个结构变量
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
} book;
我们来分析每一条语句 首先先是struct关键字标志着 我们要定义一个结构体 Books 是这个结构体的标签 这里可以通俗的理解为是我们用户自定义的一个数据类型 类型名是Books 和int类型类似 一个是官方定义的基本数据类型 一个是我们程序员自己定义的
{}里面的是结构体成员 对结构体成员这里没有任何要求 可以是基本数据类型 可以是指针 也可以是结构体类型
book 是这个结构体变量的名字
还有以下三种用法:
//此声明声明了拥有3个成员的结构体,分别为整型的a,字符型的b和双精度的c
//同时又声明了结构体变量s1
//这个结构体并没有标明其标签
struct
{
int a;
char b;
double c;
} s1;
//此声明声明了拥有3个成员的结构体,分别为整型的a,字符型的b和双精度的c
//结构体的标签被命名为SIMPLE,没有声明变量
struct SIMPLE
{
int a;
char b;
double c;
};
//用SIMPLE标签的结构体,另外声明了变量t1、t2、t3
struct SIMPLE t1, t2[20], *t3;
//也可以用typedef创建新类型
typedef struct
{
int a;
char b;
double c;
} Simple2;
//现在可以用Simple2作为类型声明新的结构体变量
Simple2 u1, u2[20], *u3;
首先看第一种 没有声明标签,我们只声明了结构体变量s1
2:声明了标签但是没有声明变量 我们可以后续定义SIMPLE类型的变量
3:用typedef 声明一个新的数据类型 是Simple2
1.3 结构体变量的初始化
和其它类型变量一样,对结构体变量可以在定义时指定初始值
示例:结合上面说的三种定义 我们分别对应三种初始化
结构体变量初始化就是对里面的成员进行初始化
1 示例:
#include <stdio.h>
int main ()
{
struct name
{
char a[4];
int num;
}s1={{'p','d','x'},1};
printf("%s\n",s1.a);
printf("%d\n",s1.num);
return 0;
}
2 示例:
#include <stdio.h>
int main ()
{
struct
{
char a[4];
int num;
}s1={{'p','d','x'},1};
printf("%s\n",s1.a);
printf("%d\n",s1.num);
return 0;
}
3 示例:
#include <stdio.h>
int main ()
{
struct SIMPLE
{
char a[4];
int num;
};
struct SIMPLE s1={{'p','d','x'},1};
printf("%s\n",s1.a);
printf("%d\n",s1.num);
return 0;
}
4示例:
#include <stdio.h>
int main ()
{
typedef struct
{
char name[4];
int num;
}m;
m man={{'p','d','x'},1};
printf("%d\n",man.num);
return 0;
}
我们可以看到第一种 是最方便理解的,剩下的三种也可以完成定义和初始化 大家遇到了也需要知道分别对应的意思
1.4 访问结构体的成员
为了访问结构的成员,我们使用成员访问运算符(.)
示例:
#include <stdio.h>
#include <string.h>
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
};
int main( )
{
struct Books Book1; /* 声明 Book1,类型为 Books */
struct Books Book2; /* 声明 Book2,类型为 Books */
/* Book1 详述 */
strcpy( Book1.title, "C Programming");
strcpy( Book1.author, "Nuha Ali");
strcpy( Book1.subject, "C Programming Tutorial");
Book1.book_id = 6495407;
/* Book2 详述 */
strcpy( Book2.title, "Telecom Billing");
strcpy( Book2.author, "Zara Ali");
strcpy( Book2.subject, "Telecom Billing Tutorial");
Book2.book_id = 6495700;
/* 输出 Book1 信息 */
printf( "Book 1 title : %s\n", Book1.title);
printf( "Book 1 author : %s\n", Book1.author);
printf( "Book 1 subject : %s\n", Book1.subject);
printf( "Book 1 book_id : %d\n", Book1.book_id);
/* 输出 Book2 信息 */
printf( "Book 2 title : %s\n", Book2.title);
printf( "Book 2 author : %s\n", Book2.author);
printf( "Book 2 subject : %s\n", Book2.subject);
printf( "Book 2 book_id : %d\n", Book2.book_id);
return 0;
}
1.5结构体作为函数的参数
概述:把结构作为函数参数,传参方式与其他类型的变量或指针类似
示例:在这里我们用到了结构体book1和book2作为函数的参数
#include <stdio.h>
#include <string.h>
struct Books
{
char title[50];
};
void printbook(struct Books book)
{
printf( "Book title : %s\n", book.title);
}
int main()
{
struct Books book1;
struct Books book2;
strcpy( book1.title, "C Programming");
strcpy( book2.title, "Telecom Billing");
printbook( book1 );
printbook( book2 );
}
运行结果:
1.6指向结构的指针
概述:可以定义指向结构的指针,方式与定义指向其他类型变量的指针相似
示例:指针的类型 是由指针指向对象的类型决定
struct Books *struct_pointer;
可以在上述定义的指针变量中存储结构变量的地址。为了查找结构变量的地址,请把 & 运算符放在结构名称的前面,如下所示:
struct_pointer = &Book1;
使用指向该结构的指针访问结构的成员,必须使用 -> 运算符示例
struct_pointer->title;
示例:
#include <stdio.h>
#include <string.h>
struct Books
{
char title[50];
};
void printbook(struct Books *book)
{
printf( "Book title : %s\n", book->title);
}
int main()
{
struct Books book1;
strcpy( book1.title, "C Programming");
printbook( &book1 );
}
1.7结构体大小的计算
概述:C 语言中,我们可以使用 sizeof 运算符来计算结构体的大小,sizeof 返回的是给定类型或变量的字节大小。
对于结构体,sizeof 将返回结构体的总字节数,包括所有成员变量的大小以及可能的填充字节
注意,结构体的大小可能会受到编译器的优化和对齐规则的影响,编译器可能会在结构体中插入一些额外的填充字节以对齐结构体的成员变量,以提高内存访问效率。因此,结构体的实际大小可能会大于成员变量大小的总和
我们来看示例了解:我们在上述结构体加了一个char类型的 应该占用1个字节的大小
输出应该是29 那对不对呢 我们来看一下运行结果
#include <stdio.h>
struct Person {
char name[20];
int age;
float height;
char a;
};
int main()
{
struct Person person;
printf("结构体 Person 大小为: %zu 字节\n", sizeof(person));
return 0;
}
我们可以看到是32字节为什么呢?
这里是涉及到结构体自动补齐 在char虽然占用1字节,但是由于对齐规则 系统仍给了四个字节的空间大小
那什么是对齐规则呢?
结构体中成员变量分配的空间是按照成员变量中占用空间最大的来作为分配单位,同样成员变量的存储空间也是不能跨分配单位的,如果当前的空间不足,则会存储到下一个分配单位中
上例代码中 我们最大的是int类型是4个字节 char name[20],占用了20个字节是int类型占用空间的整数倍 所以不需要对齐 char a;占用一个字节 自动对齐为4个字节
我们来看示例2:结构体只有char类型 占用空间最大的就是一个字节
#include <stdio.h>
struct Person {
char name[20];
char a;
};
int main()
{
struct Person person;
printf("结构体 Person 大小为: %zu 字节\n", sizeof(person));
return 0;
}
所以 这里是不需要进行对齐的 占用空间就是21字节
二共用体
2.1概述
概述:共用体是一种特殊的数据类型,允许您在相同的内存位置存储不同的数据类型。您可以定义一个带有多成员的共用体,但是任何时候只能有一个成员带有值。共用体提供了一种使用相同的内存位置的有效方式
是不是很迷糊 什么是相同的内存位置储存不同的数据类型,我们知道 不同的数据类型是占用了不同的内存空间 不同的变量是占用了不同的内存位置的 共用体是所有变量用同一内存位置 所以一次只能进行赋值一个变量 因为内存位置是有且只有一个
基本格式:
union [union tag]
{
member definition;
member definition;
...
member definition;
} [one or more union variables];
union tag 是可选的,每个 member definition 是标准的变量定义,比如 int i; 或者 float f; 或者其他有效的变量定义。在共用体定义的末尾,最后一个分号之前,您可以指定一个或多个共用体变量,这是可选的
示例:
union Data
{
int i;
float f;
char str[20];
} data;
现在,Data 类型的变量可以存储一个整数、一个浮点数,或者一个字符串。这意味着一个变量(相同的内存位置)可以存储多个多种类型的数据。可以根据需要在一个共用体内使用任何内置的或者用户自定义的数据类型。
共用体占用的内存应足够存储共用体中最大的成员。例如,在上面的实例中,Data 将占用 20 个字节的内存空间,因为在各个成员中,字符串所占用的空间是最大的。下面的实例将显示上面的共用体占用的总内存大小:
#include <stdio.h>
#include <string.h>
union Data
{
int i;
float f;
char str[20];
};
int main( )
{
union Data data;
printf( "Memory size occupied by data : %ld\n", sizeof(data));
return 0;
}
运行结果:
2.2 访问共用体成员
为了访问共用体的成员,我们使用成员访问运算符(.)。成员访问运算符是共用体变量名称和我们要访问的共用体成员之间的一个句号。您可以使用 union 关键字来定义共用体类型的变量。下面的实例演示了共用体的用法:
#include <stdio.h>
#include <string.h>
union Data
{
int i;
float f;
char str[20];
};
int main( )
{
union Data data;
data.i=1;
data.f=1.2;
strcpy( data.str, "C Programming");
printf( "data.i : %d\n", data.i);
printf( "data.f : %f\n", data.f);
printf( "data.str : %s\n", data.str);
return 0;
}
运行结果:
我们可以看到其中 i和f的值被影响了 那为什么呢? 前面我们是共用体是共用一块内存位置的,同一时间 一块内存位置只能储存一个变量 所以在赋值其他变量的时候之前赋值的,就已经失去意义了
所以最后赋值的str 依旧是可以正常访问的
正确的应该是:
#include <stdio.h>
#include <string.h>
union Data
{
int i;
float f;
char str[20];
};
int main( )
{
union Data data;
data.i = 10;
printf( "data.i : %d\n", data.i);
data.f = 220.5;
printf( "data.f : %f\n", data.f);
strcpy( data.str, "C Programming");
printf( "data.str : %s\n", data.str);
return 0;
}
所有的成员都能完好输出,因为同一时间只用到一个成员。