嵌入式C学习第四课

本文详细介绍了C语言中结构体的三种传递方式:值传递、指针传递以及成员传递,并通过示例展示了它们的区别。同时,讨论了函数指针的定义、赋值及调用方法,强调了使用函数指针调用函数的效率优势。此外,还提及了大小端存储和位域的概念。
摘要由CSDN通过智能技术生成

结构体的参数传递

参考文章:https://blog.csdn.net/lin37985/article/details/38582027

一是传递结构体变量,这是值传递,二是传递结构体指针,这是地址传递,三是传递结构体成员,当然这也分为值传递和地址传递。

以传引用调用方式传递结构比用传值方式传递结构效率高。以传值方式传递结构需要对整个结构做一份拷贝。 

下面看一个列子,student结构体中包含该学生的各种信息,我们在change函数中对其进行部分修改,再在主函数中输出其结果

1.下面传递结构体变量

#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");
}

输出结果不变

2.地址传递

<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>

可以看到,通过地址传递修改了结构体内的数据

用&stu做实参,&stu是结构体变量stu的地址。在调用函数时将该地址传送给形参p(p是指针变量)。这样p就指向stu。

在change函数中改变结构体内成员的值,在主函数中就输出了改变后的值

文件的包含

#include操作是,若后面带的是<>,则文件在安装路径中找;若后面带的是“”,则文件在源目录中找。

大小端和字节序

比特序 / 位序
我们知道一个字节有8位,也就是8个比特位。从第0位到第7位共8位。比特序就是用来描述比特位在字节中的存放顺序的。
(1)比特序分为两种:LSB 0 位序和MSB 0 位序。
LSB是指 least significant bit,MSB是指 most significant bit。
LSB 0 位序是指:字节的第0位存放数据的least significant bit,即我们的数据的最低位存放在字节的第0位。
MSB 0 位序是指:字节的第0位存放数据的most significant bit,即我们的数据的最高位存放在字节的第0位。
所以说对于代码:char *ch = 0x96; // 0x96 = 1001 0110
在这里插入图片描述
指针ch到底指向哪里呢?不难知道,如果是LSB 0 位序则显然指针ch指向最右边的也是最低位的0.
而如果是MSB 0 位序则显然指针ch指向最左边的也是最高位的1.
(2)小端CPU通常采用的是LSB 0 位序,但是大端CPU却有可能采用LSB 0 位序也有可能采用的是MSB 0 位序
(3)推荐的标准是MSB 0 位序。

大小端和字节序
术语“端”是指:在内存中的一个较大的数据,它是由各个可以被单独寻址的部分组成,这些组成部分在该数据中是以怎样的顺序存放的呢?而这个问题涉及到“端”的概念,CPU是大端还是小端决定了这些组成部分的存放顺序。这些组成部分可能是16或32位的字、8位的字节、甚至是比特位。
0x0A0B0C0D在大小端存储器上的排列顺序:
小端
在这里插入图片描述
大端
在这里插入图片描述
很显然“小端”机器符合“高高低低”的原则,即高位字节或字存放在高地址,低位字节或字存放在低地址。
另外“小端”机器中,数据在CPU的寄存器和内存中的存放顺序是一致的。

位域

参考文章:https://blog.csdn.net/zhengnianli/article/details/8zhi7386078

函数指针

函数指针定义:函数指针是指向函数的指针变量。因此“函数指针”本身首先应是指针变量,只不过该指针变量指向函数。这正如用指针变量可指向整型变量、字符型、数组一样,这里是指向函数。

其通用表达式为:类型说明符 (*函数名) (参数)


int (*fun)(int x)  //函数指针的定义
int (*fun)(int x,int y) //函数指针的定义

 

函数指针的赋值

函数指针和其他指针一样定义之后使用之前也是需要初始化。

函数指针有两个用途:调用函数做函数的参数


int (*fun)(int x,int y) //函数指针的定义
fun = &Function          //函数指针的赋值方式1
fun = Function           //函数指针的赋值方式2
x = (*fun)()             //函数指针的调用方式1
x = fun()                //函数指针的调用方式2

函数赋值的时候取地址运算符&不是必需的,因为一个函数标识符就表示了它的地址,并且赋值的时候函数不需要带圆括号;

如果是函数调用,还必须包含一个圆括号括起来的参数表。

 

函数指针的用法

我们使用指针的时候,需要通过钥匙 * 来取其指向的内存里面的值,函数指针使用也如此。通过用(*pf)取出存在这个地址上的函数,然后调用它。


char*  fun(char* p1,char* p2)
{
  int i = 0;
  i = strcmp(p1,p2);
  if(0 == i)
  {
    return p1;
  }
  else
  {
     return p2;
  }
}
int main()
{
  char * (*pf)(char* p1,char* p2);
  pf = &fun;
  (*pf)("aa","bb");
  return 0;
}

这里需要注意到是,在Visual C++6.0里,给函数指针赋值时,可以用&fun或直接用函数名fun。这是因为函数名被编译之后其实就是一个地址,所以这里两种用法没有本质的差别。

参考文章:https://blog.csdn.net/weixin_41055260/article/details/108313923?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-2&spm=1001.2101.3001.4242

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值