指针的本质
一、指针的定义
内存区域中的每个字节都对应着一个编号,编号就是地址
说某个变量的地址时都是其实地址
按变量地址存取成为[直接访问]
另一村存取变量值得方式称为[间接访问]
什么是间接访问?
把变量i的地址存到另外一个变量中。
指针变量定义格式:
基类型 *指针变量名
#include <stdio.h>
void main(){
// 直接访问
int i=5; // 变量i的地址等价于变量i的指针
printf("i=%d\n",d);
// 间接访问
// 指针变量初始化时某个变量取地址赋值,不能随机写个数
// 整型变量 的 指针 赋给 整型 的 指针变量
int *i_pointer=&i; // i_pointer是指针变量名
// 实在间接访问
printf("*i_pointer=%d\n", *i_pointer);
}
/*
"&" 取地址运算符(引用);
"*" 取值运算符(解引用);
*/
为什么*和变量名挨着?
虽然说int* i_pointer
与int *i_pointer
是相同的意思,
而且看上去前者更清晰,但是类似于int* a,b,c
很容易让人理解成a,b,c都是指针变量,
实际上b,c并非指针变量,如果要声明三个指针变量应该写成int *a, *b, *c
;所以让*和变量名挨着。
二、指针使用场景
传递
传递使用场景【在子函数内改变主函数的变量值】
// 错误写法
#include <stdio.h>
void change(int j){
j=5;
}
void main(){
int i=10;
printf("before change i=%d\n",i);
change(i);
printf("after change i=%d\n",i);
}
【错误原因】C语音的函数调用是值传递,实参赋值给形参,j地址和i地址不是同一个,所以改变j的值i不会改变
// 正确写法
#include <stdio.h>
void change(int *j){
*j=5; // *j等价于变量i,间接访问
}
void main(){
int i=10;
printf("before change i=%d\n",i);
change(&i); // 传递的是i的地址
printf("after change i=%d\n",i);
}
偏移
把对指针的加减称作指针的偏移
偏移使用场景【对指针进行加减运算】
#include <stdio.h>
#define N=5;
void main(){
int a[N]={1,2,3,4,5}; // 因为N是常量所以数组长度可以用N
int *p; // 定义一个指针变量
p=a; // a中存储的就是一个地址
// for(int i=0; i<N; i++){
// printf("%3d", a[i]);
// }
// 与上述代码等价
for(int i=0;i<N;i++){
printf("%3d", *(p+i)); // 输出1 2 3 4 5
}
printf("\n-----------------\n");
for(int i=0; i<N; i++){
printf("%3d", *(p-1));
}
printf("\n");
}
#include <stdio.h>
// 数组名作为实参传递是,弱化成指针
void change(char *d){
*d="H";
d[1]="E"; // 等价于 *(d+1)="E";
*(d+2)="L";
}
void main(){
char c[10]="hello";
change(c);
puts(c); // HELlo;
}
三、指针与malloc动态内存申请
堆空间
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void main(){
int i;
char *p;
scanf("%d",&i); // 输入要申请的空间大小
// malloc返回的void*代表无类型指针,(char *)强制类型转换,转换的类型与p的类型相同
p=(char *)malloc(i); // 使用malloc动态申请堆空间
strcry(p,"malloc success"); // 给p赋值 malloc success
puts(p); // 输出 malloc success
free(p); // 释放申请的空间【规范】释放空间时给的地址必须要是最初始的地址
printf("free success\n");
}