指针
指针类型
XX类型 + * →XX指针类型
int * 整形指针类型
char * 字符型指针类型
指针变量
用指针类型声明的变量就是指针变量
int a;//声明了一个整形变量
int* a;//声明了一个整形指针变量
指针变量赋值
指针变量存放的是变量的内存地址,赋值原则:什么类型的指针变量,就应该赋予相应类型变量的地址值:
① int* p = 0x40003a04 ; //不易解读
② int a ; char b = ‘B’ ; int *p1 = &a ; char *p2 = &b ;
内存地址
内存指RAM中的特定位置,通常以十六进制的数字表示,如0x40003a04;
在32位cpu中,地址是一个32位的无符号整形数,可以表示2^32(4GB)的地址。
指针的本质
不论什么类型的指针,存放的一定是地址,指向相应变量的地址,而地址值就是一个32位无符号的整数,所以任何指针类型的大小都是4字节;
指针类型 → unsigned int
常见的指针类型
|
类型 |
int |
char |
float |
double |
struct A{int a;int b;} |
void func() |
|
指针类型 |
int* |
char* |
float* |
double* |
struct A* |
typedef void(*pFunc)() |
定义指针并初始化
int* p1 = NULL ;
char* p1 = NULL ;
float* p1 = NULL ;
double* p1 = NULL ;
指针变量赋值
int a = 5 ; int* p1 = &a ;
获取指针变量所指变量的值
利用*获取指针所指变量的值
printf ( “%d” , *p1) ;
*的两种用法
|
类型* |
指针类型 |
|
*指针变量 |
取指针所指变量的值 |
结构体类型的指针类型
|
类型 |
struct A{int a;int b;} |
|
指针类型 |
struct A* |
定义结构体指针变量
struct A* p = NULL ;
获取结构体变量的地址
struct A {int a;int b;};
struct A a ;
printf ( “%p” , &a) ;
利用*获取结构体指针所指的变量值
struct A { int a ; int b ; } ;
struct A a = { 5 , 6 } ;
struct A* p = &a ;
printf ( “%d , %d” , (*p).a , (*p).b ) ;
利用指针变量访问结构体成员
用->引用结构体成员变量
struct A { int a ; int b ; } ;
struct A a = { 5 , 6 } ;
struct A* p = &a ;
printf ( “%d , %d” , p->a , p->b ) ;
函数指针:指针标志*在函数名前
函数:void func( ){ printf ( “func\n” ); }
函数的地址
对于函数而言,函数名就是其首地址:下述两个取到的地址相同:
printf ( “%p\n” , func );
printf ( “%p\n” , &func);
函数指针类型,不加typedef表示定义了一个函数指针变量
|
函数原型 |
void func() |
|
指针类型 |
typedef void(*pFunc)() |
函数指针的赋值
pFunc p = func ;或pFunc p = &func ;
利用函数指针变量调用函数
pFunc p = func ;
p() ; //调用func函数
复杂的函数指针
int ( * (* p )( int ) )( int );
eg. typedef int( * (* pFunc3 )( int ) )( int );
pFunc3 func3 = func;
野指针
一个指向非法内存区域的指针
①指向已经被销毁的内存
②指向无权访问的内存
①int* p = (int* )malloc( int ) ;
free(p) ; //此时的p已经变为了野指针,再取该地址的值时,是乱码
②随机将p指向一块未知的不确定的内存区域;将会导致内存被修改,引起不易察觉的BUG或系统崩溃
避免野指针
①对申请的指针进行初始化:int* p = NULL;
②释放内存后将指针置为NULL:free(p) ; p = NULL;
指针的运算:加法/减法
指针的加法:指针+N:表示将指针的值加上N*sizeof(类型)个字节
int int int int
↑ ↑
int*p p+3
指针的加法:++指针:表示将指针的值加上sizeof(类型)个字节,运行后指针p的值改变
int int int int
↑ ↑
int*p ++p
指针的减法:指针-N:表示将指针的值减去N*sizeof(类型)个字节
int int int int
↑ ↑
p-3 int*p
指针的减法:--指针:表示将指针的值减去sizeof(类型)个字节,运行后指针p的值改变
int int int int
↑ ↑
--p int*p
指针-指针:表示将两个地址值相减得到的字节数:p2-p1=3
int int int int
↑ ↑
int*p1 int*p2
一维数组
int a[5] = {1,2,3,4,5};占用一个连续的内存空间,数组中的每个值占一个字节;
一维数组的首地址是数组名或第一个元素的地址;
int a[5] = {1,2,3,4,5};
int*p = a ;
int*p = &a[0] ;
指针与数组名的区别
|
类型 |
是否可变 |
可运算 |
|
数组名 |
不可变,它是常量 |
无法++,-- |
|
指针 |
可以变,它是变量 |
可以++,-- |
利用指针访问数组元素
for( int i = 0 ; i < 5 ; i++ )
{
printf(“%d\n” , *(p+i));
}
for( int i = 0 ; i < 5 ; i++ )
{
printf(“%d\n” , *(p++));
}
for( int i = 0 ; i < 5 ; i++ )
{
printf(“%d\n” , *(a+i));//数组名是一个常量,不可改变,通过加i偏移取值,不能自加减
}
二维数组
int a[2][3] = {{1,2,3},{4,5,6}};
a[0]→ 1 2 3
a[1]→ 4 5 6
二维数组的首地址是数组名或第一个元素的地址;
二维数组指针定义
指向二维数组的指针:行指针→类型(*p)[N]
int a[2][3] = {{1,2,3},{4,5,6}};
int (*p)[3] ;
p = a ;//赋值为数组名
p = &a[0] ;//指向第一个元素的首地址
利用指针访问二维数组元素
for( int i = 0 ; i < 2 ; i++ )
for( int j = 0 ; j < 3 ; j++ )
{ printf(“%d\n” , p[i][j] ); }
for( int i = 0 ; i < 2 ; i++ )
for( int j = 0 ; j < 3 ; j++ )
{ printf( “%d\n” , *(p[i]+j) ); }//p[i]代表行指针,把p[i]看做一个数组名
for( int i = 0 ; i < 2 ; i++ )
for( int j = 0 ; j < 3 ; j++ )
{ printf( “%d\n” , *(*(p+i)+j) ); }
a[m][n]等价写法
|
类型 |
指针定义 |
赋值 |
|
行指针 |
int(*p)[N] |
a &a[N] |
|
普通指针 |
int* |
a[N] &a[M][N] |
字符串常量本身就是一个地址
hello在内存中存放为h e l l o \0
字符串常量实质就是一段内存,首地址来标识,且字符串常量的值不能改变
字符串指针
char* p = “hello”; 不能使用p[1] = ‘a’;来改变内容
给指针变量赋予字符串常量的首地址;
for( int i = 0 ; i < 5 ; i++ )
{ printf( “%c\n” , p[i] ); }
for( int i = 0 ; i < 5 ; i++ )
{ printf( “%c\n” , *(p+i) ); }
for( int i = 0 ; i < 5 ; i++ )
{ printf( “%c\n” , *(p++) ); }
指针的指针
指针变量也占用内存,所以也有内存地址
指针类型:
XX类型 * → XX指针类型
XX类型* * → XX指针类型 //指针类型
int ** //整形指针的指针类型
char ** //字符形指针的指针类型
float ** //浮点形指针的指针类型
eg.
int a = 10;
int* p = &a;
int** p = &p;
利用void传参数
void*可以传递任何类型的地址
void func(void *p)
{//将p转换为真实类型}
指针变量的强制转换
int a =5 ;
int *p = &a;
int c = (int)p;
int *p2 = (int*) c;
指针变量的强制转换
char buf[256]
int* p = (int*) buf ;
*p = 123;
printf( “%d\n” , *p);
char buf[256]
struct A{int a;int b;};
A* p = (A*) buf ;
p->a = 12;
p->b = 34;
printf( “%d,%d\n” , p->a , p->b);
原文:https://www.cnblogs.com/ren-hang/p/12644182.html