目录
1. 内存和地址
1.1内存
计算机把内存划分为⼀个个的内存单元,每个内存单元的⼤⼩取1个字节(1 byte)。其中,每个内存单元,相当于我们的学⽣宿舍,⼀个⼈字节空间⾥⾯能放8个⽐特位,就好⽐我们住的宿舍是⼋⼈间,每个⼈是⼀个⽐特位(bit)。
1.2地址
每个内存单元都有⼀个编号,这个编号就相当于我们宿舍房间的⻔牌号。有了门牌号,辅导员就可以快速查到我们寝室来检查卫生,而计算机有了这个内存单元的编号,CPU就可以快速找到⼀个内存空间。
⽣活中我们把⻔牌号叫地址,在计算机中我们把内存单元的编号也称为地址。
C语⾔中给地址起了新的名字叫:指针。
所以:内存单元的编号 == 地址 == 指针
计算机中的编址,并不是把每个字节的地址记录下来,⽽是通过硬件设计完成的。
2. 指针变量和地址
2.1取地址操作符&
在C语⾔中创建变量其实就是向内存申请空间。
创建一个整形变量a,向内存中申请4个字节,⽤于存放整数10,其中每个字节都有地址。
操作符(&)-取地址操作符
虽然整型变量占⽤4个字节,但是我们只要知道了第⼀个字节地址,顺藤摸⽠访问到4个字节的数据也是可⾏的。
2.2指针变量
存放地址的变量
#include <stdio.h>
int main()
{
int a = 6;
int* pa = &a;//取出a的地址并存储到指针变量pa中
return 0;
}
2.3拆解指针类型
int a = 10;
int* pa = a;
*表示pa是指针变量,前面的int 则说明pa指向的对象类型是int型。
2.4解引用操作符
我们把地址用指针变量存着,应为地址是有用的。可是怎么使用呢?要拿到了地址,就可以通过地址找到地址指向的对象,然后可以操作它。
通过地址找到地址指向的对象,通过解引⽤操作符(*)来实现。
2.5指针变量的大小
不同位数的机器有不同的大小
32位,指针变量大小为4字节
64位,指针变量大小为8字节
这是为什么呢?
假设是32位平台下的机器,有32根地址总线,从每根地址线出来的电信号转换位0或1的数字信号,把32根地址线产生的数字信号看做成一个地址,1字节=8比特,那么就需要4个字节用来存储。
相同平台下不同类型的指针变量的大小是一样的。
3. 指针变量类型的意义
既然相同平台下不同类型的指针变量的大小是一样的,那为什么,还分int*,char*,…?不直接造一个专属指针变量型。
因为指针的解引⽤,指针的类型决定了,对指针解引⽤的时候有多⼤的权限(⼀次能操作⼏个字节)。
指针 ± 整数
指针的类型决定了指针向前或者向后⾛⼀步有多⼤
4. const修饰指针
三种情况
const 修饰的变量,这个变量就不能被修改了。
#include <stdio.h>
int main()
{
int m = 0;
m = 20;//m是可以修改的
const int n = 0;
n = 20;//n是不能被修改的,这里报错
int* p = &n;
//但是指针可以修改,666,就像高启强想弄死李宏华,
//不能亲自动手,就找老默去干。此时老默就是指针变量p
*p = 20;
printf("n = %d\n", n);
return 0;
}
那修饰指针
#include <stdio.h>
int main()
{
int n = 20;
int m = 666;
int const * p = n;//1号
const int * p = n;//2号
p = &m;
int * const p = n;//3号
//*p = 888;
int const * const p = n;//4号
// p = &m
// *p = 888;
return 0;
}
1号和2号一样的,const 修饰 *p 即不能进行解引用操作,n的值不能改,p里的内容可以改
3号const 修饰 指针变量p, 即p里的值不能改,*p可以改,n的值可以改
4号const 修饰 *p和p,即二者都不能发生改动
结论:
const 修饰谁,谁就不能被修改了。
5. 指针运算
指针的基本运算有三种,分别是:
5.1指针± 整数
指针遍历数组
#include <stdio.h>
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int *pa = &arr[0];
int i = 0;
int size = sizeof(arr)/sizeof(arr[0]);
for(i=0; i<size; i++)
{
printf("%d ", *(pa+i));//pa+i 这⾥就是指针+整数
}
return 0;
}
5.2指针-指针
求字符串的长度
#include <stdio.h>
int my_strlen(char *s)//求字符串的长度
{
char *p = s;
while(*p != '\0' )
{
p++;
}
return p-s;
}
int main()
{
printf("%d\n", my_strlen("abc"));
return 0;
}
5.3指针的关系运算
#include<stdio.h>
int main()
{
int a[] = {0,1,2};
int *pa = a;
int* pb = a + 1;
if (pa < pb)
{
printf("pa < pb");
}
else
{
printf("pa > pb");//输出的结果
}
return 0;
}
6. 野指针及预防
野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
导致野指针的原因 | 解决
1.指针未初始化 |||| 指针初始化
2.指针越界访问 |||| 注意界限
3.指针指向的空间释放 | 用完及时置NULL
7. assert断⾔
assert断⾔⽤于在运⾏时确保程序符合指定条件,如果不符合,就报错终⽌运⾏。assert断⾔使⽤对程序员来说是⾮常友好的。直接报出错误在第几行。
8. 指针的使⽤和传址调⽤
交换数字(传值)
实参传递给形参的时候,形参会单独创建⼀份临时空间来接收实参,对形参的修改并不影响实参。
交换数字(传址)
交换数字成功。