Last active
April 14, 2021 14:17
-
-
Save lixingcong/35935f6b3e93a2b7e6cb8787c41fae75 to your computer and use it in GitHub Desktop.
C各种指针:数组指针,函数指针,回调函数,指针的引用,指针的指针
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include "math.h" | |
// 数组指针 | |
using namespace std; | |
const int COL = 2; | |
void printRowData(int* p) | |
{ | |
for (int i = 0; i < COL; ++i) | |
cout << *(p + i) << ","; | |
} | |
int main() | |
{ | |
int ROW; | |
int(*ptr)[COL]; // 数组指针(行指针),若自增1,则跳到COL个元素后(下一行) | |
cout << "column count = " << COL << "\n"; | |
while (cout << "input row count:\n" && cin >> ROW) { | |
ptr = new int[ROW][COL]; | |
for (int i = 0; i < ROW; ++i) { | |
for (int j = 0; j < COL; ++j) { | |
cout << "input a number of (row, col) = (" << i << "," << j << "):\n"; | |
cin >> *(*(ptr + i) + j); | |
} | |
} | |
// 按照ptr访问方式 | |
cout << "output via ptr:" << endl; | |
for (int i = 0; i < ROW; ++i) { | |
for (int j = 0; j < COL; ++j) { | |
cout << *(*(ptr + i) + j) << ","; | |
} | |
cout << endl; | |
} | |
// 按照传参数方式打印(此时数组指针退化成普通指针,再传入到函数中) | |
cout << "output via calling function:" << endl; | |
for (int i = 0; i < ROW; ++i) { | |
printRowData(*(ptr + i)); | |
cout << endl; | |
} | |
delete[] ptr; | |
cout << "----------------" << endl; | |
} | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
数组指针和指针数组的区别 | |
数组指针(也称行指针) | |
定义 int (*p)[n]; | |
()优先级高,首先说明p是一个指针,指向一个整型的一维数组,这个一维数组的长度是n,也可以说是p的步长。也就是说执行p+1时,p要跨过n个整型数据的长度。 | |
如要将二维数组赋给一指针,应这样赋值: | |
int a[3][4]; | |
int (*p)[4]; //该语句是定义一个数组指针,指向含4个元素的一维数组。 | |
p=a; //将该二维数组的首地址赋给p,也就是a[0]或&a[0][0] | |
p++; //该语句执行过后,也就是p=p+1;p跨过行a[0][]指向了行a[1][] | |
所以数组指针也称指向一维数组的指针,亦称行指针。 | |
指针数组 | |
定义 int* p[n]; | |
[]优先级高,先与p结合成为一个数组,再由int*说明这是一个整型指针数组,它有n个指针类型的数组元素。这里执行p+1是错误的,这样赋值也是错误的:p=a;因为p是个不可知的表示,只存在p[0]、p[1]、p[2]...p[n-1],而且它们分别是指针变量可以用来存放变量地址。但可以这样 *p=a; 这里*p表示指针数组第一个元素的值,a的首地址的值。 | |
如要将二维数组赋给一指针数组: | |
int* p[3]; | |
int a[3][4]; | |
for(i=0;i<3;i++) | |
p[i]=a[i]; | |
这里int* p[3] 表示一个一维数组内存放着三个int*指针变量,分别是p[0]、p[1]、p[2] | |
所以要分别赋值。 | |
这样两者的区别就豁然开朗了,数组指针只是一个指针变量,似乎是C语言里专门用来指向二维数组的,它占有内存中一个指针的存储空间。指针数组是多个指针变量,以数组形式存在内存当中,占有多个指针的存储空间。 | |
还需要说明的一点就是,同时用来指向二维数组时,其引用和用数组名引用都是一样的。 | |
比如要表示数组中i行j列一个元素: | |
*(p[i]+j)、*(*(p+i)+j)、(*(p+i))[j]、p[i][j] | |
优先级:()>[]>* | |
http://www.cnblogs.com/hongcha717/archive/2010/10/24/1859780.html |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// http://stackoverflow.com/questions/4295432/typedef-function-pointer | |
#include <iostream> | |
using namespace std; | |
#if 1 | |
typedef char* (*my_handler)(char *str); | |
// 指针函数 | |
char* print_a(char* str){ | |
return str+1; | |
} | |
// 函数指针 | |
void foo(my_handler handler, char* str){ | |
cout<<(*handler)(str)<<endl; | |
} | |
int main(int argc, char** argv) { | |
char a[]="fuckyou"; | |
my_handler h = &print_a; | |
cout<<(*h)(a)<<endl; | |
foo(h,a); | |
return 0; | |
} | |
#else | |
typedef void (*my_handler)(char* str); | |
void print_a(char* str){ | |
cout<<str<<endl; | |
} | |
void foo(my_handler handler, char* str){ | |
(*handler)(str); | |
} | |
int main(int argc, char** argv) { | |
char a[]="fuckyou"; | |
my_handler h = &print_a; | |
(*h)(a); | |
foo(h,a); | |
return 0; | |
} | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1、指针函数是指带指针的函数,即本质是一个函数。函数返回类型是某一类型的指针. | |
首先它是一个函数,只不过这个函数的返回值是一个地址值。函数返回值必须用同类型的指针变量来接受。所以经常使用在返回数组的某一元素地址上。 | |
返回值类型* 函数名 (参数) | |
int* f (int x,int y); | |
2、函数指针是指向函数的指针变量,即本质是一个指针变量。 | |
其实下面的“函数名”不能称为函数名,应该叫做:指针的变量名。这个特殊的指针指向一个返回整型值的函数。指针的声明笔削和它指向函数的声明保持一致。 | |
返回值类型 (*函数名) (参数) | |
int (*f) (int x,int y); | |
3、使用typedef定义函数指针,常用于callback函数声明。 | |
typedef is a language construct that associates a name to a type. | |
You use it the same way you would use the original type, for instance | |
typedef int myinteger; | |
typedef char* mystring; | |
typedef void (*myfunc)(); | |
using them like | |
myinteger i; // is equivalent to int i; | |
mystring s; // is the same as char* s; | |
myfunc f; // compile equally as void (*f)(); | |
4、给函数指针赋值,就是为函数指针指定一个函数名称,赋值的取地址符号"&"是可选的,却是推荐使用的。使用时取值"*"也是可选的,推荐使用。 | |
#include <iostream> | |
int foo(int a){ | |
return a; | |
} | |
int main(){ | |
typedef int (*FuncPtr)(int); | |
FuncPtr p1=foo; | |
FuncPtr p2=&foo; | |
std::cout<<p1(200)<<std::endl; | |
std::cout<<(*p2)(200)<<std::endl; | |
return 0; | |
} | |
注意C++中的成员函数指针。对于赋值,你必须要加“&”;对于使用,你还得指定类实例,真麻烦。 | |
class C1{ | |
public: | |
int foo(int a){ | |
return a; | |
} | |
}; | |
int main(){ | |
typedef int (C1::*FuncPtr)(int); | |
FuncPtr p=&C1::foo; | |
C1 c1; | |
std::cout<<(c1.*p)(1); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
using namespace std; | |
// 指向指针的指针 | |
int main(){ | |
int i = 5, j = 6, k = 7; | |
// ---------------------------------------------------- | |
cout<<"case 1\n"; | |
int* ip1 = &i; | |
int* ip2 = &j; | |
/* | |
* i: [5] j: [6] k: [7] | |
* ^ ^ | |
* | | | |
* ip1: [*] ip2: [*] | |
*/ | |
cout<<"ip1="<<ip1<<endl; | |
cout<<"ip2="<<ip2<<endl; | |
cout<<"*ip1="<<*ip1<<endl; | |
cout<<"*ip2="<<*ip2<<endl; | |
// ---------------------------------------------------- | |
cout<<"\ncase 2\n"; | |
int **ipp = &ip1; // 指向指针的指针 | |
/* | |
* i: [5] j: [6] k: [7] | |
* ^ ^ | |
* | | | |
* ip1: [*] ip2: [*] | |
* ^ | |
* | | |
* ipp: [*] | |
*/ | |
cout<<"*ip1="<<*ip1<<endl; | |
cout<<"*ipp="<<*ipp<<endl; // 输出ip1的地址 | |
cout<<"**ipp="<<**ipp<<endl; | |
// ---------------------------------------------------- | |
cout<<"\ncase 3\n"; | |
*ipp = ip2; | |
/* | |
* i: [5] j: [6] k: [7] | |
* ^ ^ | |
* | | | |
* ----------- | | |
* | | | |
* | | | |
* ip1: [*] ip2: [*] | |
* ^ | |
* | | |
* ipp: [*] | |
*/ | |
cout<<"*ip2="<<*ip2<<endl; | |
cout<<"*ipp="<<*ipp<<endl; // 输出ip2的地址 | |
cout<<"**ipp="<<**ipp<<endl; | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
如何理解指向指针的指针? | |
http://blog.jobbole.com/60647/ | |
让我们暂时忘掉那些关于指针的各种类比。指针实际上存放的是内存的地址。 | |
& 符号的意思是取地址,也就是返回一个对象在内存中的地址。 | |
* 符号的意思是取得一个指针所指向的对象。 也就是如果一个指针保存着一个内存地址,那么它就返回在那个地址的对象。 | |
所以当你这么写时 *ipp = ip2,实际上是把 ipp 存的地址所对应的对象,也就是 ip1 取到,然后把 ip2 存的值赋值给 ip1,也就是 j 的地址。 | |
简单点就是: | |
&:取址。 | |
* :取值。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
// std::tr1::function | |
#include <tr1/functional> // gcc header | |
//#include <functional> // Visual Studio header | |
#include <string> | |
#include <sstream> | |
using namespace std; | |
// 定义几种类型的callback原型,一种不带参,另一种带参 | |
typedef tr1::function< int () > FUNC_PARAMS_0; | |
typedef tr1::function< int (const string&) > FUNC_PARAMS_1; | |
typedef tr1::function< int (int, int) > FUNC_PARAMS_2; | |
void InterfaceFunc( const string& a , const string& b , FUNC_PARAMS_1 f ) | |
{//测试用接口函数,将a+b得到的字符串转成整数并打印出来,f是回调函数 | |
cout << f(a+b) << endl; | |
} | |
int f1( const string& str ) | |
{//正常函数 | |
cout << "int f1( const string& str )" << endl; | |
stringstream ss; | |
ss << str; | |
int result; | |
ss >> result; | |
return result; | |
} | |
class F2 | |
{ | |
public: | |
int operator()( const string& str ) | |
{//仿函数 | |
cout << "int F2::operator()( const string& str )" << endl; | |
stringstream ss; | |
ss << str; | |
int result; | |
ss >> result; | |
return result; | |
} | |
}; | |
class F3 | |
{ | |
public: | |
int f3( const string& str ) | |
{//类内非静态成员函数 | |
cout << "int F3::f3( const string& str )" << endl; | |
stringstream ss; | |
ss << str; | |
int result; | |
ss >> result; | |
return result; | |
} | |
}; | |
class F4 | |
{ | |
public: | |
static int f4( const string& str ) | |
{//类内静态成员函数 | |
cout << "static int F4::f4( const string& str )" << endl; | |
stringstream ss; | |
ss << str; | |
int result; | |
ss >> result; | |
return result; | |
} | |
}; | |
class F5 | |
{ | |
FUNC_PARAMS_0 func_p0; | |
FUNC_PARAMS_1 func_p1; | |
FUNC_PARAMS_2 func_p2; | |
public: | |
int f5_params_0() | |
{ | |
cout << "static int F5::f5_params_0( )" << endl; | |
return 0; | |
} | |
int f5_params_1(const string& str ) | |
{ | |
cout << "static int F5::f5_params_1( const string& str )" << endl; | |
cout << str << endl; | |
return 0; | |
} | |
int f5_params_2(int a, int b) | |
{ | |
cout << "static int F5::f5_params_2( int a, int b )" << endl; | |
cout << a << '+' << b << '=' << a+b << endl; | |
return 0; | |
} | |
void setCallBack() | |
{//在类内绑定一个非静态成员函数作为callback | |
// 若cb函数无参数,bind不需第三个参数 | |
func_p0=tr1::bind( &F5::f5_params_0 ,this); | |
// 若cb函数带有至少一个参数,bind需要增加相应的函数参数tr1::placeholders::_1..2...3...以此类推 | |
func_p1=tr1::bind( &F5::f5_params_1 ,this, tr1::placeholders::_1); | |
func_p2=tr1::bind( &F5::f5_params_2 ,this, tr1::placeholders::_1, tr1::placeholders::_2); | |
} | |
void runCallBack() | |
{ | |
func_p0(); | |
func_p1("100"); | |
func_p2(100,200); | |
} | |
}; | |
int main() | |
{ | |
string a = "123"; | |
string b = "456"; | |
//FUNC接受正常函数指针 | |
InterfaceFunc( a , b , f1 ); | |
cout << endl; | |
//FUNC接受仿函数 | |
InterfaceFunc( a , b , F2() ); | |
cout << endl; | |
//FUNC接受类内非静态成员函数 | |
F3 f; | |
InterfaceFunc( a , b , tr1::bind( &F3::f3 , &f , tr1::placeholders::_1 ) ); | |
cout << endl; | |
//FUNC接受类内静态成员函数 | |
InterfaceFunc( a , b , F4::f4 ); | |
cout << endl; | |
//FUNC存在于类里面 | |
F5 f5; | |
f5.setCallBack(); | |
f5.runCallBack(); | |
cout << endl; | |
cin.ignore(); // 回车键结束 | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
《tr1::function对象作回调函数技术总结》 | |
原文地址:http://blog.csdn.net/this_capslock/article/details/38564719 | |
使用C++的TR1中中包含一个function模板类和bind模板函数。使用它们可以实现类似函数指针的功能,但是比函数指针更加灵活。 | |
对于tr1::function对象可以这么理解:它能接受任何可调用物,只要可调用物的的签名式兼容于需求端即可,比如函数指针,仿函数对象,成员函数指针 | |
先自定义了一种function类型FUNC,它接受所有参数为const string&并且返回值是 int的签名对象。函数InterfaceFunc第三个参数是一个FUNC对象,当作回调函数使用 | |
这里需要特别注意下,第三次让FUNC接受类内非静态成员函数时,使用了tr1::bind( &F3::f3 , &f , tr1::placeholders::_1 )这样东西作为参数, | |
它的含义是:让&f作为F3::f3函数中的第1个参数,因为对于类内非静态成员函数,它有一个隐含的第一参数:this指针,因为成员函数是存储位置是在对象之外的,只根据F3::f3的地址无法得知具体对哪个对象操作,tr1::bind的作用正是告诉F3::f3,它隐含的this参数指向的是f这个已经定义好的对象,剩下的事情就和其它情况一样了。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 指针的引用 | |
#include <iostream> | |
void function1(int** pp) | |
{ | |
**pp=100; | |
*pp=NULL; | |
} | |
void function2(int*& ref) // compile fail in C, but ok in C++ | |
{ | |
*ref=200; | |
ref=NULL; | |
} | |
void function3(int* p) // p: pass by value | |
{ | |
*p=300; | |
p=NULL; // could not change the value of p | |
} | |
int main() | |
{ | |
int a=999; | |
int* ptr; | |
int** ptr_ptr; | |
std::cout<<"a="<<a<<std::endl; | |
ptr=&a; | |
ptr_ptr=&ptr; | |
function1(ptr_ptr); | |
std::cout<<"p1: a="<<a<<", ptr="<<ptr<<std::endl; | |
ptr=&a; | |
ptr_ptr=&ptr; | |
function2(ptr); | |
std::cout<<"p2: a="<<a<<", ptr="<<ptr<<std::endl; | |
ptr=&a; | |
ptr_ptr=&ptr; | |
function3(ptr); | |
std::cout<<"p3: a="<<a<<", ptr="<<ptr<<std::endl; | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
《指针的指针和指针的引用》 | |
原文地址:http://blog.csdn.net/luoshenfu001/article/details/8601494 | |
在下列函数声明中,为什么要同时使用*和&符号?以及什么场合使用这种声明方式? | |
void func1( MYCLASS *&pBuildingElement ); | |
先来看“int **pp”和“int *&rp”区别。前者是一个指向指针的指针;后者是一个指针的引用。如果这样看不明白的话,变换一下就清楚了: | |
typedef int* LPINT; | |
LPINT *pp; | |
LPINT &rp; | |
而指针的指针和指针的引用作为传递参数时,如demo5.cpp的两个函数function1和2在被调用时,编译器编译的二进制代码都将传递一个双重指针,只不过两者的调用方法不同,达到的效果都是能修改指针指向的地址 | |
但是demo5.cpp的函数function3在被调用时,无法修改指针的地址。 | |
可见,“引用”仅仅是为了给重载操作符提供了方便之门,其本质和指针是没有区别的。所以只要你碰到*&,就应该想到**。也就是说这个函数修改或可能修改调用者的指针,而调用者象普通变量一样传递这个指针,不使用地址操作符&。 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment