C指针复习(一)

  • 指针类型的大小为8字节.

1.运算符优先级

1.::{作用域}
2.(){函数调用,类型构造:type(exp)},[]{下标},.{成员选择},->{成员选择}
3.++{后置},--{后置},typeid{类型id},explicit_cast{四种类型转换}
4.++{前置},--{前置},~{取反},!{逻辑非},-{一元负},+{一元正},\*{指针指向值},&{取地址},(){老式类型转换},sizeof{对象大小}
5.sizeof{类型或参数包的大小},new{分配内存},delete{释放内存},noexcept{能否抛出异常}
6.->\*{指向成员中的指针},.\*{指向成员中的指针}
7.*,/,%
8.+,-
9.<<,>>
10.<,>,<=,>=
11.==,!=
12.&

2. 指针自身类型

从语法的角度看, 只要把指针声明语句里的指针名去掉, 剩下的部分就是这个指针的类型.这是指针本身所具有的类型.

int *ptr; //指针类型是 int *
int **ptr1; //指针类型是 int **
int (*ptr2)[3]; //指针类型是 int(*)[3]
int *(*ptr3)[4]; //指针类型是 int*(*)[4]

3. 指针所指向的类型

当通过指针来访问指针所指向的内存区域时, 指针所指向的类型决定了编译器将把那片内存区里的内容当做什么来看待.
从语法角度看, 只需把指针声明语句中的指针名和名字左边的指针声明符*去掉, 剩下的就是指针所指向的类型.

int *ptr; //指针所指向的类型是 int
int **ptr1; //指针所指向的类型是 int *
int (*ptr2)[3]; //指针所指向的类型是 int()[3]
int *(*ptr3)[3]; //指针所指向的类型是  int *()[3]

在指针的算数运算中, 指针所指向的类型有很大的作用, 它将决定到步长.

4. 指针的算数运算

指针可以加上或者减去一个整数, 指针的这种运算的意义和通常的数值的加减运算的意义是不一样的, 它是以单元为单位的.

当一个指针 ptr 加/减一个整数 n 后.

  • 结果是一个新的指针 ptr_new, ptr_new 的类型和 ptr_old 类型相同.
  • ptr_new 所指向的类型和 ptr_old 所指向的类型也相同.
  • ptr_new 的值将比 ptr_old的值增加/减少 n*sizeof(ptr_old所指向的类型)个字节.

也就是说 ptr_new 所指向的内存区域将比 ptr_old 所指向的内存区域向高/低地址方向移动了 n*sizeof(ptr_old所指向的类型)个字节.

指针和指针进行加减: 两个指针无法进行加法运算, 因为相加厚, 得到的结果指向一个不知所向的地方.

指针自身可以进行加减1操作, 不过一般是用在数组中.

int arr[4] = {1,2,3,4};
int *arr1 = arr;
printf("arr1++: %p \n", arr1);
arr1++;
printf("arr1++: %p \n", arr1);

输出结果, ++后增加了4个字节.

arr1++: 0x16b5132e0 
arr1++: 0x16b5132e4 

int arr1 指针指向的类型. 去掉,去掉指针名称, 为int类型, n=1, n*size(int)= 4.所以增加了4个字节.

例子:

int a[5] = {1,2,3,4,5}
int *p = &a;
int *p1 = a;

这两个得到的值是一致的, 但是含义不同
&a 取的是数组的地址, a 直接取的是数组首地址的地址。
所以, p++ 与 p1++ 得到的结果也不同。
p++ 是整个数组长度++, 既增加 20个字节。
p1++ 是指针移动到数组下一位。

int *p[5] = {0} // 指针数组,存放指针, 指向数组首元素地址.
int (*p)[5] = {0} //数组指针, 指向整个数组。可以理解为 p是一个指针, 指向一个数组, 数组有5个元素, 每个元素都是int类型

数组指针和指针数组的快速记忆技巧
数组指针: int (*p)[5]数组在前, 强调了数组, 存放数组.
指针数组: int *p[5] 指针在前, 强调了指针, 存放指针, 多个指针组成数组.
指向整个数组的是数组指针,
指向单个元素的是指针数组.

对数组进行取址与对普通变量取址不同.

  • 对普通变量取址得到的值是指针的地址.
  • 对数组取址得到的值是数组首元素的地址, 指向类型是整个数组
int a1 = 10;
int a2 = 20;
int a3 = 30;
int *arr[3] = {&a1, &a2, &a3};
//输出内容相同, 都为数组首元素地址
printf("%p\n", arr); //第一个元素的地址
printf("%p\n", &arr); //对数组进行取址,值为第一个元素的, 但是指向类型为整个数组

//指向地址相同, 但是输出的大小不同. 因为指向类型不同
printf("%d\n", sizeof(*arr));   //输出 8, 指向单个元素,单个元素类型为 int*, 
printf("%d\n", sizeof(*&arr));  //输出24, 指向整个数组, 3个元素,元素类型为 int* s

5. 使用指针操作数组

int main() {
    int a = 10;
    int *p =  &a;

    printf("%d\n", &a);


    //指针指向地址的值
    printf("%d\n", *p);
    //指针存储的值, 也就是a的地址.
    printf("%d\n", p);
    //指针的地址
    printf("%d --\n", &p);

    printf("---------\n");
    int a1 = 10;
    int a2 = 20;
    int a3 = 30;
    int *arr[3] = {&a1, &a2, &a3};
    //输出内容相同, 都为数组首元素地址
    printf("%p\n", arr); //第一个元素的地址
    printf("%p\n", &arr); //对数组进行取址,值为第一个元素的, 但是指向类型为整个数组
    //指向地址相同, 但是输出的大小不同. 因为指向类型不同
    printf("%d\n", sizeof(*arr));   //输出 8, 指向单个元素,单个元素类型为 int*,
    printf("%d\n", sizeof(*&arr));  //输出24, 指向整个数组, 3个元素,元素类型为 int* s
    printf("---------\n");


    //二维数组
    int p1[2][5] = {1,2,3,4,5,6,7,8,9,10};
    //值为第一行的地址, 也就是第一个元素的首地址, 但是指向类型为数组第一行
    printf("p1  = %p\n", p1);
    //值为第一行的首元素地址, 但是指向类型为整个二维数组
    printf("&p1 = %p\n", &p1);
    //值为第一行的首元素地址, 但是指向类型为单个元素的类型
    printf("*p1 = %p\n", *p1);
    //40
    printf("*&p1 的长度为: %d 个字节\n", sizeof(*&p1));
    //4
    printf("*p1  的长度为: %d 个字节\n", sizeof(**p1));
    //20
    printf("p1   的长度为: %d 个字节\n", sizeof(*p1));

    //二维数组取值-方式1 - 下标法
    printf("value = %d \n", p1[1][0]);


    //二维数组取值-方式2 - 指针法, 将p1看做2个一维数组, 每个一维数组又包含了5个元素.
    //(*value1_p)[5] 表示声明value1_p 是一个指向具有 5 个元素数组的指针。
    //value1_p = p1:这表示 value1_p 被赋值为 p1,存储的值为第一个一维数组的地址. 因此指针 value1_p 存储的值是p1首行的地址。p1[0]
    int (*value1_p)[5] = p1;
    //对 value1_p 执行加 1 操作时,即 (value1_p + 1),不是简单地将指针移动一个字节,因为它的指向类型是 int [5].
    //所以是将指针向后移动 5 个整数的大小 即移动到数组 p1 的下一行的起始地址。
    //换句话说,(value1_p + 1) 后得到了一个指向p1[1]的指针, 指针存储的值为 p1[1]的地址
    //第一次解引用: 对指向p1[1]的指针取值, 得到了p1[1]的地址.
    //第二次解引用: 得到了第一个元素的值. 既p1[1][0]
    printf("value = %d \n", **(value1_p+1));
    printf("value = %d \n", *(*(value1_p+1)+1));


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

推荐阅读更多精彩内容