c语言之指针
指针
- 表示一些复杂的数据结构
- 快速的传递数据
- 使函数返回一个以上的值
- 能够直接访问硬件
- 能够方便的处理字符串
- 是理解面向对象语言中引用的基础
指针就是地址,地址就是指针
地址就是内存单元的编号, 内存地址用十六进制表示
指针变量是存放地址的变量
指针和指针变量是两个不同的概念
但是要注意:通常我们叙述时会把指针变量简称为指针,实际它们含义并不一样
总结:指针是C语言的灵魂
#include <stdio.h> int main(void) { int i = 5; int * p; int * q; p = &i; //*q = p; //语法编译会出错,int *类型不能赋值给int类型 //*q = *p; //error ,q没有赋值 p = q; //q是垃圾值,q赋值给p,p也编程垃圾值 printf("%d", *q); //13行 /* q的空间是属于本程序的,所有本程序可以读写q的内容 但是如果q内部是垃圾值,则本程序不能读写*q的内容 因为*q所代表的内存单元的控制权限并没有分配给本程序 所以本程序运行到13行就会立即报错 */ return 0; }
指针的定义
地址
内存单元的编号
从0开始的非负整数
范围:
指针
指针就是地址,地址就是指针
指针变量就是存放内存单元编号的变量,或者说指针变量就是存放内存地址的变量
指针的本质就是一个操作受限的非负整数
1 #include <stdio.h> 2 3 int main(void) 4 { 5 int * p; //p是变量的名字,int * 表示p变量存放的是int类型变量的地址 6 //int * p;不表示定义了一个名字叫做*p的变量 7 //int * p;应该这样理解:p是变量名,p变量的数据类型是int *类型 8 // 所谓的int *类型实际 就是存放int变量地址的类型 9 int i=3; 10 int j; 11 12 //p = i;//error,因为类型不一致,p只能存放int类型变量的地址,不能存放int类型变量的值 13 //p = 55;//error ,原因同上 14 15 p = &i; 16 /* 17 1.p保存了i的地址,因此p指向i 18 2.p不是i,i也不是p,更准确的说:修改p的值不影响i的值,修改i的值也不影响p的值 19 3.如果一个指针变量指向了某个普通变量,则 20 *指针变量 就完全等价于 普通变量 21 例子: 22 如果p是个指针变量,并且p存放了普通变量i的地址 23 则p指向了普通变量i 24 *p 就完全等同于 i 25 * 或者说:在所有出现*p的地方都可以替换成i 26 在所有出现i的地方都可以替换成*p 27 28 *p 就是以p的内容为地址的变量 29 */ 30 31 j = *p; //等价于 j = i; 32 printf("i=%d,j=%d,*p=%d\n",i,j,*p); 33 return 0; 34 35 }
指针的分类
基本类型指针
# include <stdio.h> void huhuan_1(int, int); void huhuan_2(int *, int *); void huhuan_3(int *, int *); int main(void) { int a = 3; int b = 5; huhuan_3(&a, &b); printf("a = %d,b = %d\n", a, b); return 0; } //不能完成互换功能 void huhuan(int p, int q) { int t = 0; t = p; p = q; q = t; } //不能完成互换功能 void huhuan_2(int* p, int* q) { int* t; //如果要互换p和q的值,则t必须是int *,不能是int,否则会出错 t = p; p = q; q = t; } void huhuan_3(int* p, int* q) { int t; //如果要互换*p和*q的值,则t必须定义成int,不能是int *,否则会出错 t = *p; //p是int *.*p是int *p = *q; *q = t; }
*的含义
- 乘法
- 定义指针变量
- int * p;定义了一个名字叫p的变量,int *表示p只能存放int变量的地址
- 指针运算符
- 该运算符放在已经定义好的指针变量的前面
- 如果p是一个已经定义好的指针变量
- 则*p表示 以p的内容为地址的变量
如何通过被调函数修改主调函数普通变量的值
- 实参必须为该普通变量的地址
- 形参必须为指针变量
- 在被调函数中通过
- *形参名=....的方式就可以修改主调函数相关变量的值
# include <stdio.h> int f(int i, int j) { return 100; } void g(int* p, int* q) { *p = 1; *q = 2; } int main(void) { int a = 3, b = 5; g(&a, &b); printf("%d %d\n", a, b); }
指针和数组
指针和一维数组
一维数组名
#include <stdio.h> int main(void) { int a[5]; //a是数组名 5是数组元素的个数 元素就是变量a[0]--a[4] // int a[3][4]; //3行4列 a[0][0]是第一个元素 啊a[i][j]第i+1行j+1列 printf("%#X\n", &a[0]); printf("%#X\n", a); return 0; }
- 一维数组名是个指针常量
- 它存放的是一维数组第一个元素的地址
- 它的值不能被改变
- 一维数组名指向的是数组的第一个元素
下标和指针的关系
如果p是个指针变量,则
p[i]永远等价于 *(p+i)
确定一个一维数组需要几个参数【如果一个函数要处理一个一维数组,则需要接收该数组的哪些信息】
# include <stdio.h> //f函数可以输出任何一个一维数组的内容 void f(int * pArr,int len) { int i; for (int i=0;i<len;i++) printf("%d ", * (pArr + i)); printf("\n"); } int main(void) { int a[5] = { 1,2,3,4,5 }; int b[6] = { -1,-2,-3,4,5,-6 }; int c[100] = { 1,99,22,33 }; f(a,5); //a是int * f(b, 6); f(c, 100); return 0; }
需要两个参数:
- 数组第一个元素的地址
- 数组的长度
#include <stdio.h> /* 一定要明白 5行的pArr[3]和12行 14行的a[3]是同一个变量 */ void f(int* pArr, int len) { pArr[3] = 88; //5 } int main(void) { int a[6] = { 1,2,3,4,5,6 }; printf("%d\n", a[3]); //4 12行 f(a, 6); printf("%d\n", a[3]); //88 14行 }
#include <stdio.h> void f(int* pArr, int len) { int i; for (i = 0;i < len, i++) { printf("%d ", pArr[i]);//*(pArr+i)等价于pArr[i]也等价于b[i]也等价于*(b+i) } printf("\n"); } int main(void) { int a[5] = { 1,2,3,4,5 }; int b[6] = { -1,-2,-3,4,5,-6 }; int c[100] = { 1,99,22,33 }; f(b, 6); return 0; }
指针变量的运算
指针变量不能相加 不能相乘 不能相除
#include <stdio.h> int main(void) { int i = 5; int j = 10; int * p = &i; int * q = &j; int a[5]; p = &a[1]; q = &a[4]; printf("p和q所指向的单元相隔%d个单元\n", q - p); }
如果两个指针变量指向的是同一块连续空间中不同的存储单元,则这两个指针变量才可以相减
一个指针变量到底占几个字节
sizeof(数据类型)
功能:返回值就是该数据类型所占的字节数
例子:sizeof(int)=4 sizeof(char)=1 sizeof(double)=8
sizeof(变量名)
功能:返回值就是该数据类型所占的字节数
假设p指向char类型变量(1个字节)
假设q指向int类型变量(4个字节)
假设r指向double类型变量(8个字节)
p q r本身所占的字节数是否一样
总结:一个指针变量,无论它指向的变量占几个字节该指针变量本身只占四个字节
一个变量的地址使用该变量首字节的地址来表示