【指针】02.指针与函数、结构体指针
【嵌入式八股】一、语言篇(本专栏)https://www.nowcoder.com/creation/manager/columnDetail/mwQPeM
【嵌入式八股】二、计算机基础篇https://www.nowcoder.com/creation/manager/columnDetail/Mg5Lym
【嵌入式八股】三、硬件篇https://www.nowcoder.com/creation/manager/columnDetail/MRVDlM
【嵌入式八股】四、嵌入式Linux篇https://www.nowcoder.com/creation/manager/columnDetail/MQ2bb0
指针与函数
函数传参
传入参数:
1. 指针作为函数参数。
2. 同常有const关键字修饰。
3. 指针指向有效区域, 在函数内部做读操作。
传出参数:
1. 指针作为函数参数。
2. 在函数调用之前,指针指向的空间可以无意义,但必须有效。
3. 在函数内部,做写操作。
4。函数调用结束后,充当函数返回值。
传入传出参数:
1. 指针作为函数参数。
1. 在函数调用之前,指针指向的空间有实际意义。
3. 在函数内部,先做读操作,后做写操作。 4. 函数调用结束后,充当函数返回值。
19.使用指针传递大容量参数
在C语言中,当函数参数较大时,为了避免传递复制数据导致内存开销较大,可以使用指针来传递参数。下面是使用指针传递大容量参数的示例:
#include <stdio.h>
#include <stdlib.h>
void func(int *array, int size) { // 定义函数,传递指针和数组大小
int i;
for (i = 0; i < size; i++) {
printf("%d ", array[i]); // 输出数组中的元素
}
printf("\n");
}
int main() {
int size = 1000000; // 声明数组大小
int *array = (int *)malloc(size * sizeof(int)); // 动态分配内存,创建数组
// 初始化数组
int i;
for (i = 0; i < size; i++) {
array[i] = i;
}
func(array, size); // 通过指针传递参数
free(array); // 释放内存
return 0;
}
在上述代码中,我们首先使用malloc()
动态分配了一个包含1000000个整型元素的数组。然后在main()
函数中初始化数组,并通过指针调用func()
函数来访问数组中的元素。在func()
函数中,我们使用了指针*array
来访问数组中的元素,使用size
参数指定了数组的大小。
函数中的形参定义的是一个int 型指针,那么传入的就需要是一个地址,可以是数组名,也就是数组的首地址,可以是对一个数据取地址&a,然后函数内使用就是array[1]或*(array+1),或 *a
需要注意的是,在使用指针传递参数时,需要确保指针指向的内存区域是有效的,并且在使用完毕后需要释放内存,以免造成内存泄漏。
20.使用指针传递输出(多个)参数
一般加了const就是传递参数或数组的;不加就是要返回数据的
在C语言中,可以使用指针来传递输出参数。指针指向的变量在函数内部被修改后,可以通过指针返回到调用者的代码中。下面是使用指针传递输出参数的示例:
#include <stdio.h>
void func(const int *a, const int *b, int *sum, int *diff) {
*sum = *a + *b; // 计算a和b的和,通过指针返回
*diff = *a - *b; // 计算a和b的差,通过指针返回
}
int main() {
int a = 10, b = 5, sum, diff; // 定义变量
func(&a, &b, &sum, &diff); // 通过指针传递参数
printf("sum=%d, diff=%d\n", sum, diff); // 输出结果
return 0;
}
21.交换两个数
#include <stdio.h>
void swap(int *x,int *y) //x=&a,y=&b 值拷贝(实参 &a,&b 拷贝给形参x,y),这里拷贝的是地址
{
//通过的地址,间接找到变量的内容,进行交换
int temp;
temp =*x;
*x=*y;
*y = temp;
}
int main()
{
int a=3,b=4;
swap(&a,&b); //通过传递地址,来交换指向的内容
//实参是地址
printf("a=%d,b=%d\n",a,b);
return 0;
}
指针函数和函数指针
22.函数指针和指针函数有什么区别?
函数指针 如果在程序中定义了一个函数,那么在编译时系统就会为这个函数代码分配一段存储空间,这段存储空间的首地址称为这个函数的地址。而且函数名表示的就是这个地址。既然是地址我们就可以定义一个指针变量来存放,这个指针变量就叫作函数指针变量,简称函数指针。
int(*p)(int, int);
这个语句就定义了一个指向函数的指针变量 p。首先它是一个指针变量,所以要有一个“* ”,即(* p); 其次前面的 int 表示这个指针变量可以指向返回值类型为 int 型的函数;后面括号中的两个 int 表示这个指针变量可以指向有两个参数且都是 int 型的函数。所以合起来这个语句的意思就是:定义了一个指针变量 p,该指针变量可以指向返回值类型为 int 型,且有两个整型参数的函数。p 的类型为 int(*) (int,int) 。 我们看到,函数指针的定义就是将“函数声明”中的“函数名”改成“(指针变量名)”。但是这里需要注意的 是:“(指针变量名)”两端的括号不能省略,括号改变了运算符的优先级。如果省略了括号,就不是定义函数指针而是一个函数声明了,即声明了一个返回值类型为指针型的函数。 最后需要注意的是,指向函数的指针变量没有 ++ 和 -- 运算。
# include <stdio.h>
int Max(int x, int y)
{
return x>y?x:y;
}
int main(void) {
int(*p)(int, int); //定义一个函数指针
int a, b, c;
p = Max; //把函数Max赋给指针变量p, 使p指向Max函数
printf("please enter a and b:");
scanf("%d%d", &a, &b);
c = (*p)(a, b); //通过函数指针调用Max函数
//或者c=p(a, b); 【两种函数指针的调用方式】
printf("a = %d\nb = %d\nmax = %d\n", a, b, c);
return 0;
}
linux内核中的file_operation结构体中就是一大堆函数指针,具体操作函数编写后注册即可,用户在文件系统中调用系统调用函数的名字都是函数指针的名字。
struct file_operations {
struct module *owner;//拥有该结构的模块的指针,一般为THIS_MODULES
loff_t (*llseek) (struct file *, loff_t, int);//用来修改文件当前的读写位置
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);//从设备中同步读取数据
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);//向设备发送数据
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);//初始化一个异步的读取操作
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);//初始化一个异步的写入操作
int (*readdir) (struct file *, void *, filldir_t);//仅用于读取目录,对于设备文件,该字段为NULL
unsigned int (*poll) (struct file *, struct poll_table_struct *); //轮询函数,判断目前是否可以进行非阻塞的读写或写入
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); //执行设备I/O控制命令
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); //不使用BLK文件系统,将使用此种函数指针代替ioctl
long (*compat_ioctl) (struct file *, unsigned int, unsigned long); //在64位系统上,32位的ioctl调用将使用此函数指针代替
int (*mmap) (struct file *, struct vm_area_struct *); //用于请求将设备内存映射到进程地址空间
int (*open) (struct inode *, struct file *); //打开
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *); //关闭
int (*fsync) (struct file *, struct dentry *, int datasync); //刷新待处理的数据
int (*aio_fsync) (struct kiocb *, int datasync); //异步刷新待处理的数据
int (*fasync) (int, struct file *, int); //通知设备FASYNC标志发生变化
int (*lock) (struct file *, int, struct file_lock *);
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
int (*check_flags)(int);
int (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
int (*setlease)(struct file *, long, struct file_lock **);
};
struct file_operations fops = {
.read = device_read,
.write = device_write,
.open = device_open,
.release = device_release
};
指针函数 首先它是一个函数,只不过这个函数的返回值是一个地址值。函数返回值必须用同类型的指针变量来接受,也就是说,指针函数一定有“函数返回值”,而且,在主调函数中,函数返回值必须赋给同类型的指针变量。
类型名 *函数名(函数参数列表);
其中,后缀运算符括号“()”表示这是一个函数,其前缀运算符星号“*”表示此函数为指针型函数,其函数值为指针,即它带回来的值的类型为指针,当调用这个函数后,将得到一个“指向返回值为…的指针(地址),“类型名”表示函数返回的指针指向的类型”。 “(函数参数列表)”中的括号为函数调用运算符,在调用语句中,即使函数不带参数,其参数表的一对括号也不能省略。其示例如下:
int *pfun(int, int);
由于“*”的优先级低于“()”的优先级,因而pfun首先和后面的“()”结合,也就意味着,pfun是一个函数。 即:
int *(pfun(int, int));
接着再和前面的“*”结合,说明这个函数的返回值是一个指针。由于前面还有一个int,也就是说,pfun 是一个返回值为整型指针的函数。
#include <stdio.h>
float *find(float(*pionter)[4],int n);//函数声明
int main(void) {
static float score[][4]={{60,70,80,90},{56,89,34,45},{34,23,56,45}};
float *p;
int i,m;
printf("Enter the number to be found:");
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
查阅整理上千份嵌入式面经,将相关资料汇集于此,主要包括: 0.简历面试 1.语言篇【本专栏】 2.计算机基础 3.硬件篇 4.嵌入式Linux (建议PC端查看)