=============================
int *p=NULL;
func(p);
void func(int *p)
{
p=(int *)malloc(sizeof(int)*10);
memset(p,0,sizeof(p));
p[0]=1;
}
===================================
int *ptr=NULL;
func(&ptr);
void func(int **p)
{
*p=(int *)malloc(sizeof(int)*10);
memset(*p,0,sizeof(*p));
*p[0]=1;
}
======================================
==================================================================================================================================================================
指针值为空作为函数参数传入
2018年05月19日 11:25:48 AmelieLiu 阅读数:809
下面以一个例子来引出这种错误:
-
#include <iostream>
-
using namespace std;
-
#include <stdlib.h>
-
#include <string.h>
-
void func(int *p)
-
{
-
p = (int *)malloc(sizeof(int) * 10);
-
memset(p, 0, sizeof(p));
-
p[0] = 1;
-
}
-
int main()
-
{
-
int *p = NULL;
-
func(p);
-
cout << p[0] << endl;
-
return 0;
-
}
扫描二维码关注公众号,回复: 5612666 查看本文章
一个很简单的函数,就是给*p
在函数中分配空间并将p[0]
置成1,最后打印输出p[0]
。但是运行的结果却是segmengt fault
。
我们通过查看这段程序的汇编代码来分析一下出现段错误的原因。
-
Dump of assembler code for function func(int*):
-
0x00000000004008cd <+0>: push %rbp
-
0x00000000004008ce <+1>: mov %rsp,%rbp
-
0x00000000004008d1 <+4>: sub $0x20,%rsp
-
0x00000000004008d5 <+8>: mov %rdi,-0x18(%rbp)
-
0x00000000004008d9 <+12>: mov $0x28,%eax
-
0x00000000004008de <+17>: mov %rax,%rdi
-
0x00000000004008e1 <+20>: callq 0x400780 <malloc@plt>
-
0x00000000004008e6 <+25>: mov %rax,-0x8(%rbp)
-
0x00000000004008ea <+29>: mov -0x8(%rbp),%rax
-
0x00000000004008ee <+33>: mov $0x8,%edx
-
0x00000000004008f3 <+38>: mov $0x0,%esi
-
0x00000000004008f8 <+43>: mov %rax,%rdi
-
0x00000000004008fb <+46>: callq 0x400750 <memset@plt>
-
0x0000000000400900 <+51>: mov -0x8(%rbp),%rax
-
0x0000000000400904 <+55>: movl $0x1,(%rax)
-
0x000000000040090a <+61>: leaveq
-
0x000000000040090b <+62>: retq
-
End of assembler dump.
重点放在
-
sub $0x20,%rbp
-
mov %rdi,-0x18(%rbp)
这两句汇编代码上。
sub $0x20,%rbp
的意思是给栈分配0x20
大小的空间。
而mov %rdi,-0x18(%rbp)
的意思是把函数的第一个参数的值压入栈中存储。
这说明了什么?说明了函数中的*p
其实是一个临时变量,和主函数并不是同一个*p
了。给临时变量申请内存并赋值当前不能反映到主函数的*p
上,所以主函数的*p
还是个空指针,而打印空指针当然就段错误了。
下面介绍两种解决方法:
1.函数返回临时指针的地址:
-
#include <iostream>
-
using namespace std;
-
#include <stdlib.h>
-
#include <string.h>
-
int* func(int *p)
-
{
-
//此时的p是个临时指针
-
p = (int *)malloc(sizeof(int) * 10);
-
memset(p, 0, sizeof(p));
-
p[0] = 1;
-
return p; //返回地址
-
}
-
int main()
-
{
-
int *p = NULL;
-
p = func(p);
-
cout << p[0] << endl;
-
return 0;
-
}
2.传入指向指针的指针:
-
#include <iostream>
-
using namespace std;
-
#include <stdlib.h>
-
#include <string.h>
-
//*p存储的是main函数*ptr的地址
-
void func(int **p)
-
{
-
*p = (int *)malloc(sizeof(int) * 10);
-
memset(*p, 0, sizeof(*p));
-
*p[0] = 1;
-
}
-
int main()
-
{
-
int *ptr = NULL;
-
func(&ptr);
-
cout << ptr[0] << endl;
-
return 0;
-
}
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Move_now/article/details/71944689
==================================================================================================================================================================
c++函数参数或返回值为函数指针
C++中函数指针的形式为:返回值类型 + 参数类型,函数没有值类型,但是却可以声明函数的指针,因为函数是可寻址的,存放在内存中的代码段,可以从指针访问。
函数指针可以声明为:
void (*pF)(void);
// ^括号1
// ^括号2
其中pF为参数为空,返回值也为空的函数类型,因为*操作符的优先级低于函数调用操作符,所以必须在*pF外加括号。
那么如何声明返回值为函数指针的函数呢?
先给出一个实例:
void (* fun() )();
// ^ 括号a
// ^括号b
// ^括号c
该函数的返回值为一个函数指针,解析下这个声明的三个括号分别代表的意义:括号a对应第一个声明中的括号1,括号c对应第一个声明中的括号2,而括号c则是该函数自身的函数调用符,可以在该括号内放入函数参数如:
//参数为一个int类型
void (* fun(int x) )();
//参数为两个int类型
void (* fun(int x, int y) )();
//参数为一个函数指针类型
void (* fun( void (*f)() ) )();
其中第三个例子的参数为一个函数指针,括号比较多,要仔细看才能够看出这个声明的结构。
============================================================================================================================================================================================================================================================================
C++函数默认参数
2018年06月13日 09:20:09 luckydaxiang 阅读数:402
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/luckydaxiang/article/details/80673900
对于带参数列表的函数,必须从右向左添加默认值。也就是说,要为某个参数设置默认值,则必须为它的右边的所有参数提供默认值:
-
int function1(int n,int m = 4,int j = 5); //有效
-
int function2(int n,int m = 6,int j); //无效
-
int function3(int k = 1,int m = 2,int n = 3); //有效
例如,function1( )原型允许调用该函数时提供1个、2个或3个参数:
-
beeps = function1(2);//即function1(2,4,5)
-
beeps = function1(1,8);//即function1(1,8,5)
-
beeps = function1(8,7,6);//即function1(8,7,6)没有使用默认参数
实参按从左到右的顺序依次被赋给相应的形参,而不能跳过任何参数。因此,下面的调用是不允许的:
beeps = function1(3,,8)//无效