当函数参数为一级指针,二级指针

这篇具有很好参考价值的文章主要介绍了当函数参数为一级指针,二级指针。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

当函数参数为一级指针,二级指针

在讲述内容之前,先讲四点重要知识

1.当传入参数时,函数形参会立即申请形参的内存空间,函数执行完毕后,形参的内存空间立即释放掉

1.指针是存放其他变量地址的变量。指针有自己的内存空间,内存空间存放的是其他变量的地址。

2.指针具体指向谁,要看指针内存空间存放的地址。存放谁的地址就指向谁。

3.函数参数传参本质:实参传给形参,都是拷贝.

指针做函数参数的本质剖析,讲述四种情况

一、传变量

#include <iostream>
using namespace std;
#include <cstring>
using namespace std;
void change(int value)
{
	cout<<"change:: "<<&value<<endl;
	value = 20;
}

int main()
{
	int a = 10;
	cout<<"main:: "<<&a<<endl;
	change(a);
	cout << a << endl;
	return 0;
}

当函数参数为一级指针,二级指针,算法

为什么a的值没发生变化,请从地址空间的角度分析

在你的代码中,函数change接收的是变量a的值,而不是它的引用或指针。这意味着在函数change中,参数value是变量a的一个副本,它们在内存中的地址是不同的。因此,当你在函数change中修改value的值时,这个改变不会影响到原始变量a

这就是为什么打印出来的地址是不同的,并且变量a的值没有发生改变。如果你想在函数中修改变量a的值,你需要使用引用或指针。例如:

void change(int& value)
{
	cout<<"change:: "<<&value<<endl;
	value = 20;
}

或者

void change(int* value)
{
	cout<<"change:: "<<value<<endl;
	*value = 20;
}

在C++中,当我们将一个变量作为参数传递给一个函数时,通常有两种方式:值传递和引用传递。

  1. 值传递:当我们通过值传递一个变量时,实际上是在内存中创建了这个变量的一个副本。这个副本有自己的内存地址,与原始变量的地址不同。因此,当我们在函数中修改这个副本的值时,原始变量的值并不会改变。
  2. 引用传递:当我们通过引用或指针传递一个变量时,我们实际上是将原始变量的内存地址传递给了函数。因此,函数中对参数的任何修改都会直接反映到原始变量上,因为它们共享同一块内存空间

二、一级指针 传地址

#include <iostream>
using namespace std;
#include <cstring>
using namespace std;
void change(int* value)
{
	cout<<"change:: "<<value<<endl;
	*value = 20;
}

int main()
{
	int a = 10;
	cout<<"main:: "<<&a<<endl;
	change(&a);
	cout << a << endl;
	return 0;
}

当函数参数为一级指针,二级指针,算法

可见value 和 a的地址是相同的

三、一级指针 判断改变p的值不会影响到函数外部的指针


#include <stdio.h>
#include <stdlib.h>
#include<iostream>
using namespace std;
void change(int *pp) { // int* pp=&Q;
	cout<<"pp的值"<<pp<<endl;
	cout<<"pp的地址"<<&pp<<endl;
	pp = (int *)malloc(sizeof(int));
	cout<<"malloc之后 pp的值"<<pp<<endl;
	cout<<"malloc之后 pp的地址"<<&pp<<endl;

	
}

int main() {
	int Q=3;
	int *p = &Q;
	cout<<"Q的地址"<<&Q<<endl;
	cout<<"p的值"<<p<<endl;
	cout<<"p的地址"<<&p<<endl;
	change(p);
	cout<<"malloc之后  p的值"<<p<<endl;
	cout<<"malloc之后  p的地址"<<&p<<endl;
	cout<<"malloc之后 Q的值 "<<*p<<endl;
	free(p);
	return 0;
}

产生中断,也就是说上面的程序存在问题,有什么问题呢?

为什么一级指针改变p的值不会影响到外部的指针

这是因为在C语言中,函数参数是通过值传递的。当你将一个一级指针作为参数传递给一个函数时,实际上传递的是这个指针的值(是它保存的内存地址,也就是它所指向的内存地址,)的一个副本。也就是说,str 的值等于 p的值,但str 本身的地址 和 p 本身的地址是不同的。

比如:

当函数参数为一级指针,二级指针,算法

因为 str 和 p 的地址是不同的,所以他们是不同的指针。

在函数内部,你可以修改这个副本(把新分配的内存地址空间赋值给p,p的值(也就是p指向的内存空间变了)),但是这个修改不会影响到原来的指针。

举个例子,假设你有一个指针p,它的值(也就是它所指向的内存地址)是0x1000。当你将p作为参数传递给一个函数时,这个函数会收到一个值为0x1000的新指针。如果你在函数内部改变这个新指针的值(例如将它设置为NULL),那么这个改变只会影响到这个新指针,而不会影响到原来的p

因此,当你在函数内部改变一级指针的值时,这个改变不会影响到外部的指针。

执行malloc 函数 之后

当函数参数为一级指针,二级指针,算法
当函数参数为一级指针,二级指针,算法

为什么指向同一个内存地址的两个一级指针,在函数内部改变这个新的一级指针的值时,这个改变不会影响到原来的p。

这是因为在C语言中,函数参数是通过值传递的。这意味着当你将一个指针(无论是一级指针还是二级指针)作为参数传递给一个函数时,实际上传递的是这个指针的值(也就是它所指向的内存地址)的一个副本。

当你传递一个一级指针p给一个函数时,函数会收到一个新的一级指针,这个新的一级指针和p有相同的值(也就是它们都指向同一个内存地址)。但是,这个新的一级指针和p并不是同一个指针(他们本身的地址不同),它们只是有相同的值而已。因此,当你在函数内部改变这个新的一级指针的值时,这个改变不会影响到原来的p

换句话说,当你在函数内部改变一级指针的值时,你实际上是改变了这个一级指针副本的值,而不是原来的一级指针p。因为副本和原来的一级指针p是两个不同的变量,它们只是恰好有相同的值(也就是它们都指向同一个内存地址)。所以,改变副本的值并不会影响到原来的一级指针p

四、二级指针 判断改变p的值不会影响到函数外部的指针

#include <stdio.h>
#include <stdlib.h>

void change(int **pp) {
    *pp = (int *)malloc(sizeof(int));
    **pp = 100;
}

int main() {
    int *p = NULL;
    change(&p);
    printf("%d\n", *p);  // 输出:100
    free(p);
    return 0;
}

在你的代码中,change函数的参数是一个二级指针pp。当你调用change(&p)时,你实际上是将指针p的地址传递给了函数。这个地址就是二级指针pp所指向的地址。

因此,pp&p实际上是同一个地址。当你在函数中通过解引用操作符*来访问并修改pp时,你实际上是在修改原始指针p的值。这就是为什么这段代码能够成功运行并正确地修改p的值。

当函数参数为一级指针,二级指针,算法
当函数参数为一级指针,二级指针,算法

为什么指向同一个一级指针的二级指针,当我在函数内部改变这个新的二级指针所指向的一级指针时,这个改变会影响到原来的一级指针。

这是因为当你传递一个二级指针到一个函数时,你实际上是传递了一个指向一级指针的指针的副本。这个副本指向的是原始一级指针的内存地址。因此,当你在函数内部改变这个二级指针所指向的一级指针时,你实际上是改变了原始一级指针的值。

举个例子,假设你有一个一级指针p,它的值(也就是它所指向的内存地址)是0x1000。然后你有一个二级指针pp,它的值(也就是它所指向的内存地址)是p的地址。当你将pp作为参数传递给一个函数时,这个函数会收到一个新的二级指针,这个新的二级指针和pp有相同的值(也就是它们都指向同一个一级指针)。但是,这个新的二级指针和pp并不是同一个二级指针,它们只是有相同的值而已。然而,由于这个新的二级指针和pp都指向同一个一级指针,所以当你在函数内部改变这个新的二级指针所指向的一级指针(例如将它设置为NULL),那么这个改变会影响到原来的一级指针。

因此,当你在函数内部改变二级指针所指向的一级指针时,这个改变会影响到外部的一级指针。

这个为什么拷贝成功了呢?

在讲述之前,先注意p是二级指针,*p是一级指针,GetMemory(&str)传参时,指针变量p申请内存空间,这时有两个内存空间,str的地址拷贝给p的内存空间,即p的内存空间的内容是str的地址,这时p指向str的内存空间—>p = &str,*p = str,p 和 str两个名字,其实是相等的,指向的是同一块内存空间(上述程序在此时是NULL)。 p = (char )malloc(sizeof(100)),在堆上面申请一个100的内存空间,返回这个内存空间的首地址赋值给p;*p是一级指针,p(str)内存空间就有值了,不再是NULL,内存空间的内容是这个地址,也就是p和str指向这块内存空间,这个内存空间可以存放100个变量的地址,所以指针是存放其他变量地址的变量还是对的。接下来的strcpy(str, “hello world”)也就成功了,free(str)释放掉str(*p)所指向的内存空间.请注意,在这个过程中,p的内存空间的地址始终是str的地址,没有改变。

以上内容纯粹个人理解,如有不对之处,欢迎批评指正。


当函数参数为一级指针,二级指针,算法
当函数参数为一级指针,二级指针,算法

总结 二级指针和一级指针作为函数参数的区别

二级指针和一级指针作为函数参数传递时的区别

一级指针和二级指针在作为函数参数传递时的主要区别在于它们可以修改的内容。

当你传递一个一级指针到一个函数时,你可以通过这个指针修改它所指向的值,但是你不能改变这个指针本身所指向的内存地址。例如:

void func(int *p) {
    *p = 5;  // 可以修改p所指向的值
    p = NULL;  // 这里改变p的值不会影响到函数外部的指针
}

而当你传递一个二级指针到一个函数时,你既可以修改这个指针所指向的值,也可以改变这个指针本身所指向的内存地址。例如:

void func(int **p) {
    **p = 5;  // 可以修改p所指向的值
    *p = NULL;  // 这里改变*p的值会影响到函数外部的指针
}

因此,如果你想在一个函数中动态地改变一个指针所指向的内存地址,你需要传递一个二级指针。如果你只是想通过一个函数来改变一个值,那么传递一级指针就足够了。

在C++中,一级指针和二级指针作为函数参数有着不同的用途。

  1. 一级指针:当我们将一个一级指针作为函数参数时,我们可以在函数内部修改该指针所指向的值,但不能改变该指针本身。例如:
void changeValue(int *p) {
    *p = 100;  // 修改p所指向的值
}

int main() {
    int a = 10;
    int *p = &a;
    changeValue(p);
    cout << a << endl;  // 输出:100
    return 0;
}

在上述代码中,我们将一级指针p作为参数传递给了changeValue函数,并在函数内部修改了p所指向的值。因此,当我们回到主函数并打印出a的值时,输出的结果是100。

  1. 二级指针:当我们将一个二级指针作为函数参数时,我们可以在函数内部修改该二级指针所指向的一级指针本身。例如:
void changePointer(int **pp) {
    *pp = (int *)malloc(sizeof(int));
    **pp = 100;  // 修改pp所指向的一级指针所指向的值
}

int main() {
    int *p = NULL;
    changePointer(&p);
    cout << *p << endl;  // 输出:100
    free(p);
    return 0;
}

在上述代码中,我们将一级指针p的地址(也就是一个二级指针)作为参数传递给了changePointer函数,并在函数内部修改了该二级指针所指向的一级指针本身。因此,当我们回到主函数并打印出*p的值时,输出的结果是100。


#include <stdio.h>
#include <stdlib.h>
#include<iostream>
using namespace std;
void change(int **npp) {
	cout<<"npp的值"<<npp<<endl;
	cout<<"npp的地址"<<&npp<<endl;
	*npp = (int *)malloc(sizeof(int));
	
	
**npp = 100;
	cout<<"malloc之后 npp的值"<<npp<<endl;
	cout<<"malloc之后 npp的地址"<<&npp<<endl;
}

int main() {
	int Q=3;
	int *p = &Q;
	int **pp=&p;
	cout<<"Q的地址"<<&Q<<endl;
	cout<<"p的值"<<p<<endl;
	cout<<"p的地址"<<&p<<endl;
	cout<<"pp的值"<<pp<<endl;
	cout<<"pp的地址"<<&pp<<endl;
	change(&p);
	cout<<"malloc之后  p的值"<<p<<endl;
	cout<<"malloc之后  p的地址"<<&p<<endl;
	cout<<"malloc之后  pp的值"<<pp<<endl;
	cout<<"malloc之后  pp的地址"<<&pp<<endl;
	cout<<"malloc之后 Q的值 "<<*p<<endl;
	free(p);
	return 0;
}为什么这段代码中 pp 和npp 操作的是同一块内存空间



当然可以。让我们用一个比喻来理解一下:

假设你有
一个房子(变量),这个房子有一个地址(指针)。你把这个地址写在一张纸上(一级指针作为函数参数),然后给了你的朋友(函数)。你的朋友可以通过这个地址找到你的房子,并且可以改变房子里面的东西(修改指针所指向的值),但是他不能改变房子的位置(不能改变指针本身)。

现在,假设你不仅把房子的地址写在纸上,而且还把这张纸的地址(二级指针)也写在另一张纸上,然后给了你的朋友。这次,你的朋友不仅可以改变房子里面的东西,还可以改变第一张纸上写的地址(可以改变一级指针本身)。这就好比他可以把第一张纸上的地址擦掉,然后写上一个新的地址。这样,当你看第一张纸时,你会发现房子的"位置"已经改变了。

希望这个比喻能帮助你理解一级指针和二级指针作为函数参数的区别!

例子


int recvMsg(int cfd, char** msg)
{
    if(msg == NULL || cfd <= 0)
    {
return -1;
    }
    // 接收数据
    // 1. 读数据头
    int len = 0;
    readn(cfd, (char*)&len, 4);
    len = ntohl(len);
    printf("数据块大小: %d\n", len);

// 根据读出的长度分配内存
    char *buf = (char*)malloc(len+1);
    int ret = readn(cfd, buf, len);
    if(ret != len)
    {
        return -1;
    }
    buf[len] = '\0';
    *msg = buf;
    
    return ret;
}

在这个函数中,二级指针msg被用作传出参数,这是因为函数需要修改外部变量的值。在函数内部,msg指向的内存被分配给了新的数据,然后这个新的地址被赋值给了*msg。如果我们只使用一级指针作为参数,那么在函数内部对指针的修改(例如分配新的内存)将不会影响到外部的指针,因为函数参数是通过值传递的。

使用二级指针作为参数允许我们在函数内部修改一级指针的值(即改变一级指针所指向的地址),这样我们就可以将新分配的内存地址传递回函数的调用者。这就是为什么在这个函数中选择二级指针作为传出参数,而不是一级指针。

如果你选择一级指针作为传出参数,那么在函数内部对指针的修改(例如分配新的内存)将不会影响到外部的指针,因为函数参数是通过值传递的。这就意味着,即使你在函数内部为指针分配了新的内存,这个新的内存地址也无法传递回函数的调用者。

下面是一个示例,展示了如果使用一级指针作为传出参数会发生什么:

void recvMsg(int cfd, char* msg)
{
    // 假设len是通过某种方式获取的
    int len = 100;
    // 分配内存
    char *buf = (char*)malloc(len+1);
    // 假设我们已经将数据读入buf
    // ...
    buf[len] = '\0';
    msg = buf;  // 这里只是修改了函数内部的msg副本,对外部的msg没有影响
}

int main() {
    char *str = NULL;
    recvMsg(cfd, str);
    // 此时str仍然是NULL,因为recvMsg函数内部对msg的修改并未影响到str
    return 0;
}

在上述代码中,recvMsg函数接收一个一级指针msg作为参数。然而,由于msg是通过值传递的,所以在函数内部对msg的修改并不会影响到外部的str。这就是为什么在调用recvMsg(cfd, str)后,str仍然是NULL
= 100;
// 分配内存
char buf = (char)malloc(len+1);
// 假设我们已经将数据读入buf
// …
buf[len] = ‘\0’;
msg = buf; // 这里只是修改了函数内部的msg副本,对外部的msg没有影响
}

int main() {
char *str = NULL;
recvMsg(cfd, str);
// 此时str仍然是NULL,因为recvMsg函数内部对msg的修改并未影响到str
return 0;
}文章来源地址https://www.toymoban.com/news/detail-735823.html




在上述代码中,`recvMsg`函数接收一个一级指针`msg`作为参数。然而,由于`msg`是通过值传递的,所以在函数内部对`msg`的修改并不会影响到外部的`str`。这就是为什么在调用`recvMsg(cfd, str)`后,`str`仍然是`NULL`。

到了这里,关于当函数参数为一级指针,二级指针的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • MyBatis的缓存,一级缓存,二级缓存

    10.1、MyBatis的一级缓存 一级缓存是SqlSession级别的,通过 同一个 SqlSession对象 查询的结果数据会被缓存,下次执行 相同的查询语句 ,就 会 从缓存中(缓存在内存里) 直接获取,不会重新访问数据库(数据库在磁盘里),也就是说就执行一次sql。一级缓存 默认开启 。 使一级

    2024年02月07日
    浏览(48)
  • Mybatis 中的一级缓存与二级缓存

      缓存的意义是将用户经常查询的数据放入缓存(内存)中去,用户去查询数据的时候就不需要从磁盘(关系型数据库)中查询,直接从缓存中查询,从而提高了查询效率,解决了高并发中系统的性能问题。Mybatis中提供一级缓存与二级缓存。   Mybatis的一级缓存是一个

    2024年02月08日
    浏览(42)
  • mybatis的一级二级缓存详解及源码解剖

    一级缓存是指在同一个SqlSession中,对于相同的查询语句和参数,第一次查询的结果会被缓存到内存中,后续的查询会直接从缓存中获取结果,而不会再次查询数据库。一级缓存是MyBatis默认开启的,可以通过在SqlSession中调用clearCache()方法来清空缓存。 二级缓存是指在多个Sq

    2024年02月05日
    浏览(53)
  • Mybatis缓存机制(一级缓存、二级缓存、三级缓存)

    缓存就是内存中的数据,常常来自对数据库查询结果的保存。 使用缓存,我们可以避免频繁与数据库进行交互,从而提高响应速度。 Mybatis的缓存分为一级缓存、二级缓存、三级缓存。 一级缓存: 作用域是同一个 SqlSession,在同一个 sqlSession 中两次执行相同的 sql 语句, 第一

    2024年02月05日
    浏览(49)
  • Mybatis学习|Mybatis缓存:一级缓存、二级缓存

    MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大的提升查询效率。 MyBatis系统中默认定义了两级缓存:一级缓存和二级缓存 默认情况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存) 二级缓存需要手动开启和配置,他是

    2024年02月09日
    浏览(35)
  • Mybatis一级缓存和二级缓存(带测试方法)

    目录 相关导读 一、什么是缓存  二、Mabtis一级缓存 (1)测试一级缓存

    2023年04月08日
    浏览(79)
  • mybatis分页、延迟加载、立即加载、一级缓存、二级缓存

    分类 : 使用Limit,来进行分页;物理分页 使用RowBounds集合来保存分页需要数据,来进行分页;逻辑分页;本质是全查,只是显示部分 使用分页插件来进行分页;物理分页 方式一: 方式二: 方式三: 首先导入两个jar包: 配置插件: 调用: 字段 含义 pageNum 当前页的页码 pa

    2024年01月18日
    浏览(54)
  • uniapp开发小程序,当二级页面返回一级页面时,触发一级页面的事件或者更新一级页面的某项数据

    二级页面代码: 有人部分博客获取上一页信息是通过这样获取的:var targetPage = pages[pages.length - 2],我这样获取显示undefined,大家可以把ages打印一下,看看内容,然后自行选择 注解: getCurrentPages() 方法来获取当前页面栈 $vm 是指Vue组件实例 一级页面代码: 每次页面切换就会

    2024年02月12日
    浏览(50)
  • 国家信息安全水平考试NISP证书(一级、二级、三级)

    NISP证书是什么? NISP证书是国家信息安全水平考试(National Information Security Test Program,简称NISP),是通过中国信息安全测评中心执行塑造国家网络空间安全优秀人才项目。国家实行网络空间安全人才培养基地经营/管理方法,并受权网安世纪科技有限公司作为国家信息安全

    2024年02月04日
    浏览(51)
  • Vue:关于如何配置一级路由和二级路由的方法

    配置一级路由 创建router文件夹,里面添加index.js文件配置以下代码:

    2024年02月09日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包