700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > C 函数参数传递一级指针和二级指针的区别

C 函数参数传递一级指针和二级指针的区别

时间:2024-04-28 02:52:26

相关推荐

C 函数参数传递一级指针和二级指针的区别

文章目录

一、概念二、函数参数为一级指针例子1、程序一:指针类型为基本数据2、程序二:参数为结构体(不是指针类型)3、程序三:参数类型为结构体指针 三、函数参数为二级指针例子1、程序四:二级指针类型为基本数据类型2、程序五:二级指针类型为结构体3、程序六:通过返回值形式给外面的指针赋值

一、概念

1、一级指针和二级指针

指针保存的只是地址,这一点不要忘了

一级指针:指向变量的指针,保存的是该变量的地址;

二级指针:指向一级指针的指针,保存的也是地址,这个地址是一级指针变量的地址;

如:

int a = 1;int* p = &a;//一级指针,p保存的是变量a的地址,*p 是取到变量a 的值int** _p = &p;//二级指针,_p保存的一级指针变量p的地址,*_p 取到的是一级指针变量p的地址,**_p 取到一级指针p所指向地址的值(这里**_p 的值是1)printf("%d\n", *p);printf("%p\n", *_p);printf("%d\n", **_p);

内存块ox0001 保存的是变量a的值1;

内存块ox0002 保存的是变量a的值的地址,如这里的ox0001;

内存块ox0003 保存的是一级指针变量p的地址,如这里的ox0002;

所以,p 拿到的值为1,_p 拿到的值是ox00002, **_p 拿到的值是1

(内存地址系统每次分配的都不一样)

二、函数参数为一级指针例子

1、程序一:指针类型为基本数据

#include <stdio.h>void fun(int* p) {int b = 100;p = &b;}int main(int argc, char* argv[]) {int a = 10;int* q=&a;printf("%d\n", a);printf("%d\n", *q);fun(q);printf("%d\n", a);printf("%d\n", *q);return 0;}

打印结果:

打印结果什么都没改变,传递了指针p进函数fun,并且改变了指针p的指向。就算外面a的值不变,但是修改了p的指向,那外面打印*p 应该是100才对,那为什么不会对外面的原始指针产生变化呢?

其实在函数传递参数时,编译器总会为每个函数参数制作一个副本,即拷贝;

例如:

void fun(int *p),指针参数p的副本为_p,编译器使_p=p,_p和p指向相同的内存空间,如果在函数内修改了_p所指向的内容,就会导致p的内容也做相应的改变;

但如果在函数内_p申请了新的内存空间或者指向其他内存空间,则_p指向了新的内存空间,而p依旧指向原来的内存空间,因此函数返回后p还是原来的p;

这样的话,不但没有实现功能,反而每次都申请新的内存空间,而又得不到释放,因为没有将该内存空间的地址传递出来,容易造成内存泄露;

所以,函数fun的函数体经过编译器编译之后的内容如下:

void fun(int* p) {int* _p = p;int b = 100;_p = &b;}

传递进来的一级指针在函数体内部的操作,全部都是对副本指针_p的操作;

如这里的函数体只是修改副本指针的指向,而原指针p还是指向变量a的地址,所以不会让外层的变量和指针产生变化;修改函数fun:

void fun(int* p) {*p = 100;}

打印结果:

这里就是修改了副本指针的指向内容,而副本指针指向的内容为变量a的值,所以就会对外面的变量产生变化。

2、程序二:参数为结构体(不是指针类型)

typedef struct User {char* name;int age;};void set_user_info(User user) {user.name = "lisi";user.age = 30;}int main(int argc, char* argv[]) {User user;user.name = "zhangsan";user.age = 26;printf("name=%s,age=%d\n", user.name, user.age);set_user_info(user);printf("name=%s,age=%d\n", user.name, user.age);return 0;}

打印结果:

原因和程序一一样,函数参数发生了拷贝,经过编译后的函数set_user_info的内容如下:

void set_user_info(User user) {//这里的user 是原数据User _user = user;//拷贝_user.name = "lisi";_user.age = 30;}

函数体内,变量_user 和原始的变量user 是两个不同的变量,也是两块不同的地址;程序打印如下:

void set_user_info(User _user) {_user.name = "lisi";_user.age = 30;printf("user=%p\n", &_user);}int main(int argc, char* argv[]) {User user;user.name = "zhangsan";user.age = 26;printf("user=%p\n", &user);set_user_info(user);return 0;}

所以在函数体内的操作只是对副本的变量的操作,不会对原始变量的内容产生改变

3、程序三:参数类型为结构体指针

功能:打印函数的参数指针和原指针是否指向同一块地址

typedef struct User {char* name;int age;};void set_user_info(User* user) {user->name = "lisi";user->age = 30;printf("user=%p\n", user);}int main(int argc, char* argv[]) {User* user;user = (User*)malloc(sizeof(User));user->name = "zhangsan";user->age = 26;printf("user=%p\n", user);set_user_info(user);free(user);//主动申请的内存也需要手动释放return 0;}

打印结果:

说明:函数参数为指针的,发生拷贝之后,副本指针很原始指针都是指向同一块地址,所以修改副本指针指向的内容时,外面的变量也会发生变化(和程序一原理一样,这里重复是针对参数的指针类型为结构体类型下),示例代码如下:

typedef struct User {char* name;int age;};void set_user_info(User* user) {user->name = "lisi";user->age = 30;}int main(int argc, char* argv[]) {User* user;user = (User*)malloc(sizeof(User));user->name = "zhangsan";user->age = 26;printf("name=%s,age=%d\n", user->name, user->age);set_user_info(user);printf("name=%s,age=%d\n", user->name, user->age);free(user);//主动申请的内存也需要手动释放return 0;}

打印结果:

so:在传递一级指针时,只有对指针所指向的内存变量做操作才是有效的;

函数中的所有操作都是对拷贝的副本指针进行操作,如果在函数中申请内存赋值给传进来的指针变量,实际上这块申请的内存是给副本指针赋值的,不是对外面的指针赋值,所以不会对外面的指针产生影响

在程序三中,需要对手动给指针变量user 申请内存,才不至于后续的操作会报:- The variable ‘user’ is being used without being initialized. 如果我们想只是申请一个指针变量,然后传递给函数,在函数中给指针赋值,需要怎么做呢? 这时候就需要使用二级指针了;

三、函数参数为二级指针例子

1、程序四:二级指针类型为基本数据类型

void fun2(int** _p) {int b = 100;//相当于开辟一块内存*_p = &b;}int main(int argc, char* argv[]) {int a = 10;int* p = &a;printf("a=%d\n", *p);// node1fun2(&p);printf("*p=%d\n", *p);// node2printf("a=%d\n", a);// node3return 0;}

打印结果:

先看node1 处的打印 a=10,这个没什么问题;

在没执行函数fun2 中的 *_p = &b 前,各个变量的指向链如下图所示

在执行之后,如下图所示

一级指针 p 保存了ox0004 的地址,所以node2打印*p 打印的是100,变量a的内容从始至终都没有修改过,所以node3打印了10。

从上图可知,在声明一级指针后,没对其进行初始化,也可使用二级指针形式,修改一级指针的指向,从而得到值;

代码如下:

void fun2(int** p) {int b = 100;//相当于开辟一块内存*p = &b;}int main(int argc, char* argv[]) {int* p;fun2(&p);printf("*p=%d\n", *p);return 0;}

打印结果

2、程序五:二级指针类型为结构体

void get_user_info(User** user) {User* _user = (User*)malloc(sizeof(User));_user->name = "lingtao";_user->age = 26;*user = _user;}int main(int argc, char* argv[]) {User* user;get_user_info(&user);printf("user.name=%s\nuser.age=%d\n", user->name, user->age);free(user);//不使用了,需要手动释放内存user = 0;return 0;}

打印结果:

3、程序六:通过返回值形式给外面的指针赋值

User* get_user_info2() {User* _user = (User*)malloc(sizeof(User));_user->name = "lingtao";_user->age = 26;return _user;}int main(int argc, char* argv[]) {User* user;//get_user_info(&user);user = get_user_info2();printf("user.name=%s\nuser.age=%d\n", user->name, user->age);free(user);//不使用了,需要手动释放内存user = 0;return 0;}

程序六就不多说了,也是发生拷贝,和传参的参数拷贝类似

SO:在传递二级指针时,只有对指针的指向做改变才是有效的;

总结:

在传递一级指针时,只有对指针所指向的内存变量做操作才是有效的;

在传递二级指针时,只有对指针的指向做改变才是有效的;

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。