c语言初阶指针

对指针的基本认识

指针最基本的用法

复制代码
int a = 10;
int* p = &a;

指针其实就是存储的地址,现在主流的机器有32位与64位,先来看32位的机器,由于有32个位,因此可以表示2^32字节的地址,因为一个地址小单元就是一个字节,所以表示2^32字节,注意,是字节,因此2^32 Byte =(2^32/2^10)MB = (2^32/2^10/2^10)GB = 2^2 GB, 也就是4G,因此它可以存储4GB的数据,于是,一个地址长度就为4字节,指针变量又是存储的地址,因此在32位系统中,指针变量长度为4字节。

同理可得,在64位操作系统中,指针变量长度为8字节

五个结论

接下来是五个结论,理解这四句话才能打好指针的基础

  1. 内存被划分为一个个的内存单元,每个内存单元的大小是1个字节
  2. 每个字节的内存单元都有一个编号,这个编号就是地址,地址在c语言中称为指针
  3. 地址要存储的话,存放在指针变量中
  4. 每个内存单元都有一个唯一的地址来标识
  5. 在32位机器上地址的大小是4个字节,所以指针变量的大小也是4个字节;同理,在64位机器上地址的大小是8个字节,所以指针变量的大小也是8个字节。

指针跳跃

但是,指针存储地址, 地址在同一个机器上位数不变,是不是指针类型的长度就是固定的呢?

请看VCR:

复制代码
#include <stdio.h>

int main(int argc, const char * argv[]) {
    int a = 10;
    int *pa = &a;
    printf("%lu\n", sizeof((int*)pa));
    printf("%lu\n", sizeof((short*)pa));
    printf("%lu\n", sizeof((char*)pa));
    printf("%lu\n", sizeof((long*)pa));
    return 0;
}

运行结果:

那么,每个类型的指针大小都是固定不变的,需要int*, short*这些指针类型干什么呢?是不是他们就没有意义了呢?

其实

指针类型是有意义的

指针类型决定了指针+1 /-1跳过几个字节

客官请看VCR:

复制代码
#include <stdio.h>

int main(int argc, const char * argv[]) {
    int a = 10;
    int *pa = &a;
    char* pc = &a;
    
    printf("pa = %p\n", pa);
    printf("pa = %p\n", pa+1);
    
    printf("pc = %p\n", pc);
    printf("pc = %p\n", pc+1);
    
    return 0;
}

运行结果

第一行第三行分别打印的是pa, pc存储的地址, 也就是变量a的地址

可以看到对于int*类型的 pa与pa+1, 他们之间的地址(0x)表示十六进制,地址相差了 e0-dc = 4字节,这也说明pa到下一个地址pa+1跳过了4个字节.

再看pc与pc+1, 他们之间的地址相差了dd-dc = 1字节,这说明pc到下一个地址pc+1跳过了一个字节,刚好是一个字符的大小

因此, 有结论

指针类型是有意义的

指针类型决定了指针+1 /-1跳过几个字节

指针解引用使用

先看指针解引用法最基础的用法:

复制代码
#include <stdio.h>

int main(int argc, const char * argv[]) {
    int a = 10;
    int *pa = &a;
    *pa = 0;
    printf("%d\n", a);
    return 0;
}

可以看到, *符号是解引用符号, 可以将指针p存储的地址取出来使用, 这里进行了a的数值的更改

更进一步, 使用指针访问数组

复制代码
int arr[] = {1,2,3,4,5,6,7,8,9,10};
    int *p = arr;

因为, arr是数组名,数组名表示数组首元素的地址等价于int* p = arr[0], 于是,

复制代码
#include <stdio.h>

int main(int argc, const char * argv[]) {
    int arr[] = {1,2,3,4,5,6,7,8,9,10};
    int *p = arr;
    for (int i=0; i<10; i++) {
        *(p+i) = 0;
    }
    for (int i=0; i<10; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
    return 0;
}

因为i为指针偏移量, 并且p是int*的指针, 一次跳过四个字节, 也就是一次跳过数组的一个元素, 访问数组下标为i的元素的地址,并将他们都置为0

于是,打印数组可以使用p+i找到下标为i的地址, 并解引用

复制代码
for (int i=0; i<10; i++) {
        printf("%d ", *(p+i));
    }

由此有一个冷门但是炫酷的小结论

因为p存储的是arr的地址

因此,可以理解为

p等价于arr

也就是 p+i等价于arr+i

解引用

*(p+i)等价于*(arr+i)都等价于arr[i]

*(arr+i)等价于arr[i]

那么有没有可能 *(i+arr)等价于i[arr]呢?

我们试试

复制代码
for (int i=0; i<10; i++) {
        printf("%d ", i[arr]);
    }

!竟然真的可以

为什么呢?

因为编译器在打印或者说访问数组arr[i]时, 会把元素首地址与偏移量取出来, 也就是使用的是*(arr+i), 所以将数组名和下标写反也是没问题滴, 小装逼方法get.

相关推荐
大龄程序员狗哥4 小时前
第25篇:Q-Learning算法解析——强化学习中的经典“价值”学习(原理解析)
人工智能·学习·算法
南境十里·墨染春水4 小时前
linux学习进展 线程同步——互斥锁
java·linux·学习
nashane6 小时前
HarmonyOS 6学习:旋转动画优化与长截图性能调优——打造丝滑交互体验的深度实践
学习·交互·harmonyos·harmonyos 5
华清远见IT开放实验室6 小时前
智能手表完整项目实现,比赛求职双向加分,基于嵌入式大赛推荐开发板(STM32U5)
stm32·单片机·嵌入式硬件·学习·智能手表·嵌入式大赛
炽烈小老头6 小时前
【 每天学习一点算法 2026/04/22】四数相加 II
学习·算法
uncle_ll6 小时前
LangChain基础学习笔记
笔记·学习·langchain·llm·rag
三品吉他手会点灯7 小时前
C语言学习笔记 - 14.C编程预备计算机专业知识 - 本讲内容概述
c语言·笔记·学习
Thanwind7 小时前
从0开始的机器学习之旅(二):监督学习,从线性回归说起
学习·机器学习·线性回归
2501_942326447 小时前
易速乐考,轻松备考
学习·教育电商
菜鸟‍7 小时前
【CVPR 2026】LitePT:更轻、更强的点云 Transformer【论文学习】
深度学习·学习·transformer