对指针的理解

指针的概念

1. 怎么理解指针

int b = 1 ;
int *a =  &b ;
int *c =  (int *)b ;
printf("指针a保存的地址是 : %d \n" ,a );
printf("指针a保存的地址中保存的值是: %d \n", *a);
printf("指针a保存的地址是 : %d \n" ,c );
printf("指针a保存的地址中保存的值是: %d \n", *c); // 无输出
  • 我的理解是一个记录内存地址的小卡片

输出:

指针a保存的地址是:0061ff10
指针a保存的地址中保存的值是:1
指针c保存的地址是:00000001
指针c保存的地址中保存的值是: 这里会报错
举个例子 , p指针这个小纸条上记录的内存地址是7338864 , 我们去内存中找到这个对应的地址 , 这个地址中保存的值 是 1

指针的类型

  • 指针的类型 有什么意义 , 不同类型指针之间有什么区别

首先 要知道 指针本身就是一种数据类型 ,示例
( sizeof(char *) == sizeof(int *) )?printf("true"):printf("false"); // printf : true

输出 :

true

那么在使用数据类型来修饰指针是用来干嘛的 ,是用来修饰 指针指向 变量 的数据类型的吗 ??? ,

我们上面做了比喻 , 说指针就是一个小纸条 ,上面记录了变量在内存的地此 ,那么 , 是不是可以把 int 类型的指针赋值 char 类型的指针 ,

int b = 1 ;
int *a =  &b ;
char *c =  (int *)&b ;
printf("指针 a 储存的地址: %p \n" ,a );
printf("指针 c 储存的地址: %p \n", c);
printf("指针 a 指向内存中的数据: %d \n" ,*a );
printf("指针 c 指向内存中的数据: %d \n", *c);

输出 :

指针 a 储存的地址: 0x0061ff14
指针 c 储存的地址: 0x0061ff14
指针 a 指向内存中的数据: 1
指针 c 指向内存中的数据: 1

没错是可以的 从结果上来看视乎没有区别

那么我们接下来看这个:
char str[] = "abcdefgh"; // 
char *pchar = str ; 
int  *pint = (int *)str; //将 char 类型的指针转换成 int 类型的
printf(" char 类型的指针 +1  的地址:%p \n" , (pchar + 1)); // char 类型的指针 +1 指针跳跃了 1个字节
printf(" char 类型的指针 +1  的地址内保存的字符:%c \n" , *(pchar + 1)); 
printf(" 字符数组 str[1]        的地址:%p \n" , &str[1]); 
printf(" 字符数组 str[1]        保存的字符:%c \n" , str[1]); 

printf(" int 类型的指针 +1   的地址:%p \n" , (pint + 1)); // int 类型的指针 +1 指针跳跃了 4个字节
printf(" int 类型的指针 +1   的地址内保存的字符:%c \n" , *(pint + 1));
printf(" 字符数组 str[4]        的地址:%p \n" , &str[4]);
printf(" 字符数组 str[4]        保存的字符:%c \n" , str[4]);

输出 :

char 类型的指针 +1 的地址:0061ff0c
char 类型的指针 +1 的地址内保存的字符:b
字符数组 str[1] 的地址:0061ff0c
字符数组 str[1] 保存的字符:b
int 类型的指针 +1 的地址:0061ff0f
int 类型的指针 +1 的地址内保存的字符:e
字符数组 str[4] 的地址:0061ff0f
字符数组 str[4] 保存的字符:e

很显然 区别这就出来了

总结:指针的类型 代表着指针+1的跳跃的字节 , 数据类型是几个字节 ,就跳跃几个字节

char + 1 跳跃 sizeof(char) == 1 个字节
int + 1 跳跃 sizeof(int) == 4 个字节
float + 1 跳跃 sizeof(float) == 4 个字节
double + 1 跳跃 sizeof(double) == 8 个字节

特殊的指针

1. 常量指针

常量指针 概念是 : 你不能通过常量指针去修改 这个地址中的数据 如:

int a = 6 ;
const int *b = &a ;
*b = 3 ; // 错误 不能通过常量指针去更新地址内保存的数据 
 a = 4 ; // 正确 不影响 a 变量正常赋值 , 

2. 无类型指针

无类型指针怎么理解呢 , 通过上面的测试 我们明白了 指针的类型 , 所以 无类型指针 本质上就是 没有跳跃力 的的指针

无类型指针有以下特点:

  1. 任何指针(包括函数指针)都可以赋值给void指针
  2. void指针赋值给其他类型的指针时都要进行转换
  3. void指针在强制转换成具体类型前,不能解引用;(即不能读取改地址里面的数值)
  4. void指针不能参与指针运算,除非进行转换;(转换前不能加减)
int     a       = 1  ;
char    b       = 'a';
int     *p_int  = &a ;
char    *p_char = &b ;
void    *p_void ;
// 任何指针(包括函数指针)都可以赋值给void指针
p_void = p_int  ; // 可正常编译执行
p_void = p_char ; // 可正常编译执行

// void指针赋值给其他类型的指针时都要进行转换 // 没转换所以报错
// p_char = p_void ; //错误代码:  error: invalid conversion from 'void*' to 'char*
p_char = (char *)p_void ; // 可正常编译执行

// void指针在强制转换成具体类型前,不能解引用
// printf(" %c \n" , *p_void); //错误代码: error: 'void*' is not a pointer-to-object type
printf(" %p \n" , p_void); //可正常编译执行

// void指针不能参与指针运算,除非进行转换;(转换前不能加减) // 
p_void = p_void + 1  ;  //警告代码: warning: pointer of type 'void *' used in arithmetic
printf(" %p \n" , p_void ); // gcc 编译器下 可以打印出地址

输出 :

0061ff0b
0061ff0c

3. 函数指针

既是 这个指针指向 的是 一个函数的地址

注意:

  1. 不符合定义的函数地址 不能保存在函数指针内
  2. 函数指针 不能参与指针运算
  3. 函数指针指针函数 是有区别的 , 函数指针是指针 , 指针函数是函数
#include<stdio.h> 

typedef int (*fp)(int,int); //这样只是定义一个函数指针类型 
int test(int a , int b){ return a + b; } // 定义 一个符合的函数 
int test2(int a , int b , int c){ return a + b + c; } // // 定义 不一个符合的函数

int main ()
{   
    // 定义 一个函数指针 
    fp fun ;  
    // fun = test2 ; //error: invalid conversion from 'int (*)(int, int, int)' to 'int (*)(int, int)'
    fun = test ; // 正常编译执行  
    printf(" %d \n" , fun(1 , 2) ) ; // 调用  
    printf("pointer fun address:%p \n" , fun ) ; 
    //warning: pointer to a function used in arithmetic
    printf("pointer fun + 1 address:%p \n" , fun + 1 ) ; 
    return 0;
}

输出 :

3
pointer fun address:00401460
pointer fun address:00401461

从结果上来看 函数指针 也是没有跳跃力的 对其做运算 结果 和无类型指针是 差不多一样

数组指针

1. 在了解 数组指针 之前我们必须先明白 数组和指针的区别

注意:

  1. 数组指针本质上是不一样的 , 是两种数据类型 ,
  2. 数组指针 在大多数情况下是可以互相转换的 ,这也是很多人被误导的地方
int arr[4] = { 1,2,3 ,4 } ;     // 定义一个int数组 
int *p_int ;                    // 定义一个int 指针 

//在多数情况下 指针 和 数组 会隐式转换
p_int = arr ;               // 这是把数组当指针用 
p_int = &arr[0] ;           // 正常对指针赋值 
printf(" p_int[0]   == %d  \n" , p_int[0] ); // 这是把指针当数组用 ,这是可以的 
printf(" *p_int     == %d  \n" , *p_int );   // 正常使用指针  

// 对数组和指针 使用 sizeof 得到的结果不同 
printf(" sizeof(arr)    == %d  \n" , sizeof(arr) );     // sizeof(arr)    == 16
printf(" sizeof(p_int)  == %d  \n" , sizeof(p_int) );   // sizeof(p_int)  == 4
// 对数组和指针 使用 & 得到的结果不同 
printf(" &arr       == %p  \n" , &arr );    // 输出数组arr 首个元素的地址 
printf(" &p_int     == %p  \n" , &p_int );  // 输出指针 p_int 的地址

输出 :

p_int[0] == 1
*p_int == 1
sizeof(arr) == 16
sizeof(p_int) == 4
&arr == 0061febc
&p_int == 0061feb8

**总结: 指针还是原来的那个小纸条 , 数组则是 变量的集合体 **

  1. 通过 sizeof 可以看出来 , 这两种数据类型 有着本质的区别 , 不要被他们之间的隐式转换 误导了
2. 数组指针 怎么理解呢 , 我们对 指针类型 的是时候做了测试 , 定义指针的类型 ,其实上就是定义指针的 跳跃力,
抛开指针的 跳跃力 ,指针只不过是一个记录内存地址的变量而已

注意:

  1. 数组指针指针数组 是有区别的 , 数组指针是指针 , 指针数组是数组
  2. 我们测试指针和数组的区别时 , 测试过在大多数情况下指针 和数组 是可以 隐式转换的 ,
    既是 : 数组指针
    那么 : 数组指针数组 数组 = 二维数组
    所以 : 数组指针二维数组
  3. 数组指针其实是复合类型的指针 , 我们验证了指针的类型代表指针的跳跃力 , 那么 数组指针的跳跃力就是类型和数组的组合
int a[5][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};  
int b[3][4] ;  

// 1. 数组指针和指针数组 是有区别的 , 数组指针是指针 , 指针数组是数组
// 这样 定义是 指针数组 , 这个本质上是数组 
// sizeof(void*[4]) == 16 , 这是定义了 4 个指针 , 然后把他们组成一个数组
int *pi[4] ;

// 定义是 数组指针 , 这个本质值上是指针  
// sizeof(void *) == 4 ,  指针 int (*p)[4] 必须指向一个 int[n][4] 的 二维数组 ,所以数组指针 也被称为 行指针 
int (*p)[4] ; 

// 2. 我们测试指针和数组的区别时 , 测试过在大多数情况下指针 和数组 是可以 隐式转换的 ,  
//    既是 : 数组 ≈  指针  
//    那么 : 数组指针  ≈  数组 数组  =  二维数组  
//    所以 : 数组指针  ≈  二维数组
int n = 3 , a1[n] , *p1 ; 
p1 = a1 ;  // 数组 ≈  指针  int a1[n]  == int (*p1)   
p = a   ;  //数组指针 ≈ 二维数组 int a[n][4]  == int (*p1)[4] , 切记 二维长度 要相等  
printf("a[1][1] = %d \n" , p[1][1]); // 也可以将 数组指针 当做二维数组来用
printf("&a[1][1] = %d \n" , *( (*(p + 1)) + 1) ); // 指针的方式使用, 注意:符号优先级 () > [] > * 

// 3.数组指针的跳跃力 就是 类型 * 数组 二维长度 的组合
printf("int  *p1 = %p \n" , p1);
printf("int  *p1 + 1 = %p \n" , p1 + 1); // int *p + 1 = sizeof(int)

printf("int (*p)[4] = %p \n" , p);
printf("int (*p)[4] + 1 = %p \n" , p + 1);// int (*p)[4] + 1 = sizeof(int) * 4

输出 :

a[1][1] = 6
&a[1][1] = 6
int *p1 = 0061fe38
int *p1 + 1 = 0061fe3c
int (*p)[4] = 0061fe9c
int (*p)[4] + 1 = 0061feac

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,616评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,020评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,078评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,040评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,154评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,265评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,298评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,072评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,491评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,795评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,970评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,654评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,272评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,985评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,815评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,852评论 2 351

推荐阅读更多精彩内容

  • 上一篇介绍了指针和数组的区别和联系,相信很多同学都已经明白了指针和数组的用法,那么如果指针和数组混合起来,你还会用...
    GLGeek阅读 2,215评论 0 6
  • 关于指针,大家肯定不陌生,一些初学者,想必会出现思绪混乱的情况,现在我就来帮大家缕一缕吧。(第一次写微博 有点小...
    Allen_HD阅读 591评论 0 1
  • Go指针理解 Go 有指针,但是没有指针运算。你不能用指针变量遍历字符串的各个字节。在 Go 中调用函数的时候,得...
    不屈真实阅读 768评论 0 2
  • 先来讲一下本人学指针的经历:大一的时候刚接触c语言对指针这东西真的是太迷了,感觉麻烦难懂不想其他语言一样。但是搞懂...
    许_ac50阅读 307评论 0 0
  • Class数据结构: getIsa( ) 为获取 isa 指向的类,isa 指向的类是对象的真实类型。 objc_...
    小李不木阅读 1,697评论 0 1