
C语言改一个变量的值有两种写法结论先放这写法一a 100; 用变量名直接改写法二*p 100; 用地址改两种改的是同一块内存只是进门的钥匙不一样。一、先看两段效果一样。int a 10;a 100;printf(“%d”, a); // 100int a 10;int *p a;*p 100;printf(“%d”, a); // 100那问题来了a 100 就够了指针图什么二、变量名是给谁看的变量名是给人看的地址才是给机器用的。计算机不认识 a 这个字母只认识地址。int a 10;实际做的事找一块内存记下它的地址比如 0x7ffd1234把 10 放进去把 “a” 和这个地址绑起来记在编译器的本子上所以你写 a编译器自动翻译成去 0x7ffd1234。a 是地址的别名。想看地址长啥样用 int a 10;printf(“值 %d\n”, a); // 10printf(“地址 %p\n”, a); // 0x7ffd1234每次运行都变a 读作 a 的地址。所以变量名和地址指的是同一块内存两把钥匙。用名字进门a 100;用地址进门先把地址存起来存它的变量叫指针再用三、指针是啥int *p a;部分意思int *p 是指针专门存 int 类型的地址a取 a 的地址int *p a;把 a 的地址存进 pp 里装的不是 10是地址。*p 的 * 叫解引用意思是顺着 p 里存的地址找过去操作那块内存。*p 100; // 顺着地址找过去把里面的值改成 100四个符号分清符号是什么a值a地址p存地址的本子*p照着地址去改四、什么时候必须用地址如果只是 a 100 和 *p 100 二选一指针确实多余。指针的用处是有些场合你拿不到变量名只拿得到地址。三个最常见的。函数想改外面的变量C 的函数传参是值传递传进去的是复印件。void change(int x) {x 100; // 改的是复印件}int main() {int a 10;change(a);printf(“%d”, a); // 10没改到}原因是 change(a) 传的是 a 的值10函数里的 x 是另开的房间放了个 10。撕掉复印件原件不动。改成传地址void change(int *p) {*p 100; // 顺着地址改原件}int main() {int a 10;change(a); // 把地址传进去printf(“%d”, a); // 100}对比参数写法调用结果传值change(int x)change(a)a 不变传地址change(int *p)change(a)a 被改函数在别的房间它不认识 a 这个名字只拿到地址。有地址才能动手。最典型的是交换两个数void swap(int *a, int *b) {int temp *a;*a *b;*b temp;}int main() {int x 1, y 2;swap(x, y);printf(“x%d, y%d”, x, y); // x2, y1}如果写成 swap(int a, int b)里面怎么换外面的 x 和 y 都不动。2. 数组数组不给每个元素起名字arr[0] arr[1] arr[2] 本身就是按位置找。int arr[3] {10, 20, 30};arr[1] 99; // 改 1 号位置arr[i] 在 C 内部等价于*(arr i) 99; // 首地址往后挪 i 格也就是说 arr[i] 本身就是用地址改数据。int arr[3] {10, 20, 30};arr[1] 99; // 下标写法*(arr 2) 88; // 指针写法printf(“%d %d %d”, arr[0], arr[1], arr[2]); // 10 99 88两种一样。数组和指针老被放一起讲就是因为它们是同一个东西的两种写法。元素一多更明显int arr[100];for (int i 0; i 100; i) {arr[i] 0;}100 个元素不可能手写 100 行。只能按位置改。3. 大结构体传值会把整个结构体复制一份费时间费内存。void print(struct Student s) { } // 复制一整份void print(struct Student *s) { } // 只传地址后面看到一堆函数参数写成指针基本都是为了这个。五、怎么选场景写法当前函数里改普通变量a 100;函数要改外面的变量传地址改数组某个元素arr[i] x;批量处理同类型数据循环 下标传大结构体传地址一句话名字能直接叫上用名字叫不上在别的函数里、在一堆数据里只能靠地址。六、变量住在哪顺带记一下变量不是随便扔的。高地址┌───────────────┐│ 栈区 │ 局部变量、函数参数 ← 自动分配释放├───────────────┤│ ↓ ││ ↑ │├───────────────┤│ 堆区 │ malloc 出来的 ← 手动分配释放├───────────────┤│ 全局/静态区 │ 全局变量、static ← 全程存在├───────────────┤│ 常量区 │ 字符串常量 ← 只读├───────────────┤│ 代码区 │ 函数的机器码 ← 只读└───────────────┘低地址int global_var 100; // 全局/静态区int global_zero; // 全局/静态区自动为 0int main() {int local 10; // 栈区char *str “hello”; // str 在栈区“hello” 在常量区int *heap malloc(40); // 堆区free(heap);}两条够用函数的局部变量在栈区函数一结束就没了。所以别返回局部变量的地址。malloc 的在堆区不 free 就一直占着这就是内存泄漏。七、两个坑改只读区char *p “hello”;p[0] ‘H’; // 崩“hello” 在常量区只读改它就崩段错误。能拿到地址 ≠ 能改。有些房间是只读的。野指针int *p a;// a 所在的函数已经结束*p 100; // 崩或者改坏别人的数据那间房早就退租了现在住的是谁不知道。规矩指针指的东西必须还活着。八、总结变量名给程序员看地址给机器看同一块内存两把钥匙。a 100; 用名字开门*p 100; 用地址开门用第二种主要是三种情况函数要改外面的变量C 是值传递数组按位置访问arr[i] 就是 *(arr i)传大块数据传地址比复制省符号表符号是什么a值a地址p存地址的变量*p照着地址去改指针不是额外加的负担它是 C 里唯一能让你碰到内存本体的手段。值和地址这层分清了后面字符串、数组、结构体、链表都会顺很多