结构体的参数传递
结构体做函数参数传递有三种方式:
(1)用结构体的单个成员作为函数参数,向函数传递结构体的单个成员(属于传值调用,不会影响相应的实参结构体的值),分为值传递和地址传递。
(2)用结构体变量做函数参数,向函数传递结构体完整结构(属于传值调用,不会影响相应的实参结构体的值),属于地址传递。
(3)用结构体指针或结构体数组作函数参数属于模拟按引用调用,会影响相应的实参结构体的值,向函数传递结构体地址,因为仅复制结构体首地址一个值给被调函数,相对于第二种方式,这种传递效率更高,属于值传递。
传递结构体变量:
#include<stdio.h>
#include<string.h>
#define format "%d\n%s\n%f\n%f\n%f\n"
struct student
{
int num;
char name[20];
float score[3];
};
void change( struct student stu );
int main()
{
struct student stu;
stu.num = 12345;
strcpy(stu.name, "Tom");
stu.score[0] = 67.5;
stu.score[1] = 89;
stu.score[2] = 78.6;
change(stu);
printf(format, stu.num, stu.name, stu.score[0], stu.score[1],stu.score[2]);
printf("\n");
return 0;
}
void change(struct student stu)
{
stu.score[0] = 100;
strcpy(stu.name, "jerry");
}
最终输出的值未改变
地址传递:
<span style="font-family:Arial Black;font-size:12px;">#include<stdio.h>
#include<string.h>
#define format "%d\n%s\n%f\n%f\n%f\n"
struct student
{
int num;
char name[20];
float score[3];
};
void change( struct student* stu );
int main()
{
struct student stu;
stu.num = 12345;
strcpy(stu.name, "Tom");
stu.score[0] = 67.5;
stu.score[1] = 89;
stu.score[2] = 78.6;
change(&stu);
printf(format, stu.num, stu.name, stu.score[0], stu.score[1],stu.score[2]);
printf("\n");
return 0;
}
void change(struct student* p)
{
p->score[0] = 100;
strcpy(p->name, "jerry");
}</span>
通过地址传递修改了结构体内的数据
文件的包含
在C语言中文件包含是指一个源文件可以将另一个源文件的全部内容包含进来。该命令的作用是在预编译时,将指定源文件的内容复制到当前文件中。文件包含是C语言预处理命令三个内容之一。
文件包含有两种格式,分别是:#include “file” 和 #include
1.使用双引号,系统首先到当前目录下查找被包含的文件,如果没找到,再到系统指定的"包含文件目录"(由用户在配置环境时设置)去找。
2.使用尖括号:直接到系统指定的"包含文件目录"去查找。
例如:
文件F1.c
#define PI 3.1415926
#define R 3
#define S PI*R*R
文件F2.c
#include "F1.c"
#include "stdio.h"
main()
{
float area=0;
printf("area=%f\n",S);
}
大小端和字节序
字节序:
字节序,简单来说,就是指的超过一个字节的数据类型在内存中存储的顺序
分类
大端字节序:高位字节数据存放在低地址处,低位数据存放在高地址处;这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;这和我们的阅读习惯一致。
小段字节序:高位字节数据存放在高地址处,低位数据存放在低地址处;这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低。
网络字节序:TCP/IP协议传输数据时,字节序默认大端。
位域
位段,C语言允许在一个结构体中以位为单位来指定其成员所占内存长度,这种以位为单位的成员称为“位段”或称“位域”( bit field) 。利用位段能够用较少的位数存储数据。
如果程序的结构中包含多个开关量,只有 TRUE/FALSE 变量,如下:
struct
{
unsigned int widthValidated;
unsigned int heightValidated;
} status;
这种结构需要 8 字节的内存空间,但在实际上,在每个变量中,我们只存储 0 或 1。在这种情况下,C 语言提供了一种更好的利用内存空间的方式。如果您在结构内使用这样的变量,您可以定义变量的宽度来告诉编译器,您将只使用这些字节。例如,上面的结构可以重写成:
struct
{
unsigned int widthValidated : 1;
unsigned int heightValidated : 1;
} status;
现在,上面的结构中,status 变量将占用 4 个字节的内存空间,但是只有 2 位被用来存储值。如果您用了 32 个变量,每一个变量宽度为 1 位,那么 status 结构将使用 4 个字节,但只要您再多用一个变量,如果使用了 33 个变量,那么它将分配内存的下一段来存储第 33 个变量,这个时候就开始使用 8 个字节。让我们看看下面的实例来理解这个概念:
#include <stdio.h>
#include <string.h>
/* 定义简单的结构 */
struct
{
unsigned int widthValidated;
unsigned int heightValidated;
} status1;
/* 定义位域结构 */
struct
{
unsigned int widthValidated : 1;
unsigned int heightValidated : 1;
} status2;
int main( )
{
printf( "Memory size occupied by status1 : %d\n", sizeof(status1));
printf( "Memory size occupied by status2 : %d\n", sizeof(status2));
return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:
Memory size occupied by status1 : 8
Memory size occupied by status2 : 4
位域声明
在结构内声明位域的形式如下:
struct
{
type [member_name] : width ;
};
下面是有关位域中变量元素的描述:
元素 | 描述 |
---|---|
type | 只能为 int(整型),unsigned int(无符号整型),signed int(有符号整型) 三种类型,决定了如何解释位域的值。 |
member_name | 位域的名称。 |
width | 位域中位的数量。宽度必须小于或等于指定类型的位宽度。 |
带有预定义宽度的变量被称为位域。位域可以存储多于 1 位的数。
函数指针
如果在程序中定义了一个函数,那么在编译时系统就会为这个函数代码分配一段存储空间,这段存储空间的首地址称为这个函数的地址。而且函数名表示的就是这个地址。既然是地址我们就可以定义一个指针变量来存放,这个指针变量就叫作函数指针变量,简称函数指针。
定义方式
函数返回值类型 (* 指针变量名) (函数参数列表);
注:“函数返回值类型”表示该指针变量可以指向具有什么返回值类型的函数;“函数参数列表”表示该指针变量可以指向具有什么参数列表的函数。这个参数列表中只需要写函数的参数类型即可。
如何用函数指针调用函数
int Func(int x); /*声明一个函数*/
int (*p) (int x); /*定义一个函数指针*/
p = Func; /*将Func函数的首地址赋给指针变量p*/