c深入剖析跨函数调用指针(多级指针)问题
2017-03-19 19:40
218 查看
在c语言中,如果想要通过函数调用来改变值,有两种方式,第一种是通过指针的传递来改变值(这种可以一次改变多个变量的值),第二种是通过方法的返回值来传递值。第一种,中传递的时候其实只是地址的传递,相对第二种的值传递来说,第一种的效率要高不少,因为第一种传递的是地址,四个字节(部分计算机)大小的地址。特别,是在c中做字符串的处理时,这种第一种情况用的非常的多,我当时也是在做字符串处理的时候遇到这些问题,然后下面我会举例,还有一些思想方法。
一、通过函数调用来交换值(一级指针)
上面的程序可以实现x和y值的交换,不知道大家,有没有这样想过,在exchangeValue方法中,为什么不能这样写
int* temp = a;
a = b;
b = temp;
这样能改变x和y的值吗?下面我们就来探讨一下这个问题
上面的程序并不能改变x和y的值,他们其实是把a和b进行交换了,x和y并没有交换,可以从地址的值中可以看出来。 00E4FB70这个地址里面存放的就是10,而00D4FB64这个地址中存放的就是20。地址是一个8位16进制的数,因为我的电脑一个指针时占4个字节也就是32位,而8位十六进制,一个十六进制相当于4个二进制,所以说,8位十六进制其实也就是32位二进制。通过exchangeValue函数传过去的是两个变量的地址,而上一个方法是对两个地址所指向的值进行了交换,而第二个交换的是地址,实际上它们是交换了a和b的值。虽然说,a和x指向的是同一个值,但是并不代表它们是同一个变量,不要误以为我们把x和y的地址进行了交换。整形x和y的地址是不能被改变的,只能改变它们的内容。
下面的这个方法也可以改变x和y的值,但是不是通过方法调用改变的,只是为了深入分析一下指针问题
上面的这个程序其实是交换了两个指针变量x和y里面的内容,本来指针变量x里面存放的是10的地址,而指针变量y中存放的是20的地址,后面通过temp指针变量,将指针变量x和y中的内容进行了交换,从而将两个指针变量所指向的int类型的值交换了。为什么指针变量x和y需要用malloc函数为其开辟空间呢,而temp指针却不需要呢?因为,如果你不给指针变量x开辟空间而是直接int* x = 10,这样会报x被使用而未初始化的异常,为什么呢?其实是因为,int* x=
10的意思是说,将10赋值以x中的内容为地址的int类型的变量,而你却没有给这个变量开辟空间,所以导致报错。而int* temp;temp = x;不需要用malloc为其开辟空间那是因为,你是将 指针变量x里面的内容赋值给了temp指针,从而让temp指针变量指向了10。
二、跨函数使用内存之二级指针
1、跨函数调用通过二级指针来给一个指针变量赋值,跨函数分配内存
2、通过二级指针实现字符串的分割
接下来,我们主要讨论一下这句代码的含义*(*str_before + i) = *(str + i),当时为了写出这句代码,我花了一下午的时间去理解跨函数使用二级指针。当时,就一直在想使用二级指针的时候**str = 'a';可以这样赋值,那我能不能通过数组去赋值呢?当时,我是这样写的**(str_before+i) = *(str+i),然后就会一直报异常,最后通过调试发现*str_before[0]可以正常赋值,而到了*str_before[1]的时候就会报异常,这是为什么呢?后面,我就仔细想了一想这句代码的含义。二级指针str_before,下面画个图方便理解
上面的图就是str_before的一个二级指针图,对于指针问题,如果不是很清楚的时候,画图理解是一个很好的方法。其中以0X开头的是内存单元的一个8位十六进制的地址。我上面的图画的不是很标准,因为在计算机中内存是一个字节大小的存储单元,也就是8位。而像0XAABB33DD这个值需要四个字节来存储,而地址一般是存的首地址。通过上面的图,我们再思考一下为什么*str_before[1]会报异常呢?因为,在c语言中[]的优先级要高于*,这样的话,*str_before[1]的意思就是,0XAABB33DD这个单元的第二个数据,而str_before[0]等于0XAABBEE11,str_before[1]这个值根本就不存在,所以导致报异常,如果改成这样(*str_before)[1]就没有问题了。现在,再来解释一下*(*str_before+i),*str_before指的就是0XAABB33DD这个单元,*str_before指向的就是0XAABBEE11中的第一个
字符,*str_before+1指向的就是0XAABBEE11中的第二个字符。而**str_before就等于字符a,*(*str_before+1)就等于字符b。最后,说一下个人感悟,作为一个程序员肯定是会遇到问题,在遇到问题的时候,怎么去高效的解决问题,这就体现了一个程序员的能力。我当时,遇到这个问题的时候,就只是想着在网上一顿乱搜,最后也没能找到答案,时间也浪费了,问题还没解决。我觉得,当我们遇到问题的时候,首先应该静下来仔细考虑想想整个程序的逻辑是怎么样的,理解每句代码究竟是什么意思。然后,再去找问题在哪,这样才能提高一个程序员解决问题的能力。最后,如果实在想不出来的话,可以请教他人,再想想自己还有那些知识点没弄明白,然后再去补短,这样才能有所提高。上面纯属个人见解,如有问题尽请留言。
一、通过函数调用来交换值(一级指针)
void exchangeValue(int* a,int* b){ //交换的时候,还是要通过第三个变量来交换两个变量的值 int temp = *a;//a的值,也就是x的值,因为我们是将x的地址传给了a,所以a就指向了x,同理b也是如此 *a = *b; *b = temp; } int main(){ int x = 10; int y = 20; exchangeValue(&x,&y); cout << x << endl;//这两句话是c++中的输出,为了方便就没写printf了 cout << y << endl;//输出结果是20和10 system("pause"); return 0; }
上面的程序可以实现x和y值的交换,不知道大家,有没有这样想过,在exchangeValue方法中,为什么不能这样写
int* temp = a;
a = b;
b = temp;
这样能改变x和y的值吗?下面我们就来探讨一下这个问题
void exchangeValue(int* a,int* b){ //交换的时候,还是要通过第三个变量来交换两个变量的值 int* temp = a;//a的值,也就是x的值,因为我们是将x的地址传给了a,所以a就指向了x,同理b也是如此 a = b; b = temp; cout << "a地址:" << a << endl;//a的地址:00E4FB64 cout << "b地址:" << b << endl;//b的地址:00E4FB70 } int main(){ int x = 10; int y = 20; cout << "x地址:" << &x << endl;//x的地址:00E4FB70 cout << "y地址:" << &y << endl;//y的地址:00E4FB64 exchangeValue(&x,&y); cout << x << endl;//这两句话是c++中的输出,为了方便就没写printf了 cout << y << endl;//输出结果是10和20 system("pause"); return 0; }
上面的程序并不能改变x和y的值,他们其实是把a和b进行交换了,x和y并没有交换,可以从地址的值中可以看出来。 00E4FB70这个地址里面存放的就是10,而00D4FB64这个地址中存放的就是20。地址是一个8位16进制的数,因为我的电脑一个指针时占4个字节也就是32位,而8位十六进制,一个十六进制相当于4个二进制,所以说,8位十六进制其实也就是32位二进制。通过exchangeValue函数传过去的是两个变量的地址,而上一个方法是对两个地址所指向的值进行了交换,而第二个交换的是地址,实际上它们是交换了a和b的值。虽然说,a和x指向的是同一个值,但是并不代表它们是同一个变量,不要误以为我们把x和y的地址进行了交换。整形x和y的地址是不能被改变的,只能改变它们的内容。
下面的这个方法也可以改变x和y的值,但是不是通过方法调用改变的,只是为了深入分析一下指针问题
int main(){ int* x = (int *)malloc(4);//这里必须的为指针变量x分配空间 *x = 10; int* y = (int *)malloc(4); *y = 20; //交换x和y的内容(并不是交换他们的值所指向的内容) int *temp; temp = x; x = y; y = temp; cout << *x << endl; cout << *y << endl; system("pause"); return 0; }
上面的这个程序其实是交换了两个指针变量x和y里面的内容,本来指针变量x里面存放的是10的地址,而指针变量y中存放的是20的地址,后面通过temp指针变量,将指针变量x和y中的内容进行了交换,从而将两个指针变量所指向的int类型的值交换了。为什么指针变量x和y需要用malloc函数为其开辟空间呢,而temp指针却不需要呢?因为,如果你不给指针变量x开辟空间而是直接int* x = 10,这样会报x被使用而未初始化的异常,为什么呢?其实是因为,int* x=
10的意思是说,将10赋值以x中的内容为地址的int类型的变量,而你却没有给这个变量开辟空间,所以导致报错。而int* temp;temp = x;不需要用malloc为其开辟空间那是因为,你是将 指针变量x里面的内容赋值给了temp指针,从而让temp指针变量指向了10。
二、跨函数使用内存之二级指针
1、跨函数调用通过二级指针来给一个指针变量赋值,跨函数分配内存
void test(int **a){ *a = (int*)malloc(sizeof(int));//这里其实在给指针变量x开辟空间,相当于在main方法中的int* x = (int*)malloc(sizeof(int)); **a = 10; } int main(){ int *x; test(&x); cout << *x << endl; system("pause"); return 0; }
2、通过二级指针实现字符串的分割
//根据第一个分割的字符串分割str字符串,返回分割字符串之前的部分和之后的部分 void str_split(char *str,char * strsubstring,char ** str_before,char ** str_after){ *str_before = (char*)calloc(strlen(str),1);//为以str_before的内容为地址的字符串开辟空间并赋初值 //malloc和calloc都是为指针变量开辟内存,malloc不会为开辟的空间初始化保留的是垃圾数据,而calloc会初始化 *str_after = (char*)calloc(strlen(str),1);//用calloc的原因是为了避免产生乱码 char * s = strstr(str,strsubstring);//根据第一个strsubstring进行分割,返回的是从strsubstring开始的一个首地址 //如果字符串str中没有strsubstring这个被分割的字符串 if (s==NULL){ **str_before = '\0'; **str_after = '\0'; }else{ //如果被分割的字符串刚好位于字符串的开头部分 if (strlen(s) == strlen(str)){ * str_after = s;//如果不想要分割的字符串可以这样写,* str_after = s+strlen(strsubstring); **str_before = '\0'; //被分割的字符串刚好位于字符串的结尾部分 }else if (strlen(s)==strlen(strsubstring)){ int i = 0; int flag = (strlen(str) - strlen(s)); while (i < flag){ *(*str_before + i) = *(str + i);//如果能理解这句代码的含义,说明真正弄懂了二级指针的含义 i++; } **str_after = '\0'; //被分割的字符位于字符串的字符串的中间 }else{ * str_after = s; int i = 0; int flag = (strlen(str) - strlen(s)); while (i < flag){ *(*str_before + i) = *(str + i); i++; } } } }
接下来,我们主要讨论一下这句代码的含义*(*str_before + i) = *(str + i),当时为了写出这句代码,我花了一下午的时间去理解跨函数使用二级指针。当时,就一直在想使用二级指针的时候**str = 'a';可以这样赋值,那我能不能通过数组去赋值呢?当时,我是这样写的**(str_before+i) = *(str+i),然后就会一直报异常,最后通过调试发现*str_before[0]可以正常赋值,而到了*str_before[1]的时候就会报异常,这是为什么呢?后面,我就仔细想了一想这句代码的含义。二级指针str_before,下面画个图方便理解
上面的图就是str_before的一个二级指针图,对于指针问题,如果不是很清楚的时候,画图理解是一个很好的方法。其中以0X开头的是内存单元的一个8位十六进制的地址。我上面的图画的不是很标准,因为在计算机中内存是一个字节大小的存储单元,也就是8位。而像0XAABB33DD这个值需要四个字节来存储,而地址一般是存的首地址。通过上面的图,我们再思考一下为什么*str_before[1]会报异常呢?因为,在c语言中[]的优先级要高于*,这样的话,*str_before[1]的意思就是,0XAABB33DD这个单元的第二个数据,而str_before[0]等于0XAABBEE11,str_before[1]这个值根本就不存在,所以导致报异常,如果改成这样(*str_before)[1]就没有问题了。现在,再来解释一下*(*str_before+i),*str_before指的就是0XAABB33DD这个单元,*str_before指向的就是0XAABBEE11中的第一个
字符,*str_before+1指向的就是0XAABBEE11中的第二个字符。而**str_before就等于字符a,*(*str_before+1)就等于字符b。最后,说一下个人感悟,作为一个程序员肯定是会遇到问题,在遇到问题的时候,怎么去高效的解决问题,这就体现了一个程序员的能力。我当时,遇到这个问题的时候,就只是想着在网上一顿乱搜,最后也没能找到答案,时间也浪费了,问题还没解决。我觉得,当我们遇到问题的时候,首先应该静下来仔细考虑想想整个程序的逻辑是怎么样的,理解每句代码究竟是什么意思。然后,再去找问题在哪,这样才能提高一个程序员解决问题的能力。最后,如果实在想不出来的话,可以请教他人,再想想自己还有那些知识点没弄明白,然后再去补短,这样才能有所提高。上面纯属个人见解,如有问题尽请留言。
相关文章推荐
- 函数指针的深入剖析与讲解
- typedef&nbsp;和函数指针问题深入总结
- 函数调用缺少参数列表;请使用“&Student::Printf”创建指向成员的指针 问题解析
- 【转】C++编程中用指针直接调用类成员函数问题及其解决方法
- 深入剖析php执行原理(4):函数的调用
- QT信号槽的六个优点(虽然直接调用函数也可解决问题,但要在具体的函数中传递指针,多对一和解除关系也够麻烦的)
- 一级指针,二级指针在函数调用传址问题。在子函数中分配内存。
- C/C++中函数的传值调用、指针调用、引用调用问题
- c指针在函数调用过程中的问题
- 巧妙解决问题:&CMFCcodeDlg::RunCommands”创建指向成员的指针。MFC多线程调用要求调用的接口必须是全局函数或静态成员函数
- Javascript学习之深入剖析函数调用
- 关于类成员函数指针的调用问题
- typedef&nbsp;和函数指针问题深入总结
- C++内存分配、函数调用(值传递、指针传递、引用传递)、返回值问题
- C# 调用DLL多级指针和多维数组问题。
- C++ 中的指针、引用以及函数调用中的问题
- 函数调用参数为指针时,实参跟形参的问题
- 关于局部指针变量 函数调用后 该指针的问题
- c++ 父类指针转换为子类指针后调用子类的成员函数问题
- 函数指针的深入剖析与讲解