【参考课程:B站 BV1cq4y1U7sg BV1Vm4y1r7jY】
目录
指针是什么
内存单元的编号--地址(地址指向内存单元)--地址也被称为指针
//存放地址的变量--指针变量
*指针的大小:在32位平台是4个字节,在64位平台是8个字节
指针和指针类型
指针大小与指针类型无关
#include<stdio.h> int main() { //【64位平台】 printf("%lld\n", sizeof(int*)); //8 printf("%lld\n", sizeof(float*)); //8 printf("%lld\n", sizeof(char*)); //8 printf("%lld\n", sizeof(double*)); //8 printf("%lld\n", sizeof(short*)); //8 printf("%lld\n", sizeof(long long*)); //8 printf("%lld\n", sizeof(long*)); //8 return 0; }
指针类型决定了指针解引用时的访问权限有多大
int main() { int a = 0x11223344; int* pa = &a; *pa = 0; return 0; }
int main() { int a = 0x11223344; char* pc = &a; *pc = 0; return 0; }
指针类型决定了指针走一步的步长有多大
#include<stdio.h> int main() { int arr[10] = { 0 }; int* pi = arr; char* pc = arr; printf("%p\n", pi); printf("%p\n", pi+1); printf("%p\n", pc); printf("%p\n", pc+1); return 0; }
//指针+n 向前走n步
//指针 - n 向后走n步
野指针
野指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
野指针产生的原因
- 指针未初始化
int main() { int* p;//p是一个局部的指针变量,局部不初始化--默认为随机值 *p = 20;//非法访问内存了 //此处p为【野指针】 return 0; }
-
指针越界访问
int main() { int arr[10] = { 1 }; int* p = arr; int i = 0; for (i = 0; i <= 10; i++)//i==10时越过arr开辟的内存空间了 { *p = i; p++; } return 0; }
-
指针指向的空间释放了→非法访问
int* test() { int a = 10; //a是函数test的局部变量 return &a; //a在离开test时即销毁→其开辟的内存空间被释放 } int main() { int* p = test(); //p储存的是a的地址,但离开test函数a即被销毁 *p = 20; //再通过p储存的(曾经a的)地址已经无法访问a了→这里的p是一个【野指针】 return 0; }
如何规避野指针
- 初始化指针
#include<stdio.h> //包含NULL的定义 int main() { //当不知道p应该初始化为什么地址时,直接初始化为NULL int* p = NULL; //此处NULL定义:#define NULL ((void *)0) //知道p应该初始化为什么地址 int a = 10; int* pa = &a; return 0; }
- 小心指针越界
c语言本身不会检查越界,需要我们自己注意
- 指针指向空间释放及时置NULL
- 指针使用之前检查有效性
#include<stdio.h> int main() { //初始化指针 int* p = NULL;//空指针也不能直接用//把p初始化为空指针方便检查指针有效性 //检查指针有效性 if (p != NULL) *p = 10; return 0; }
指针运算
指针 + - 整数 \\ 指针的关系运算(比大小)
//指针+n 向前走n步 //指针 - n 向后走n步
#include<stdio.h>
int main()
{
int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
int* p = arr;
int* p9 = arr + 9; //指针加整数
for (p=arr;p <= p9;p++) //指针的关系运算
{
printf("%d ", *p);
} //程序结果:将arr数列打印出来
return 0;
}
*标注规定:允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较[这样比较不算越界],但是不允许与指向第一个元素之前的那个内存位置的指针进行比较
指针 - 指针
指针相减得到的是两个指针之间的元素个数
//指针相减的前提是两个指针指向同一块空间
#include<stdio.h>
int main()
{
int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
printf("%d\n", &arr[9] - &arr[0]); //9
return 0;
}
【练习】编写函数求字符串的长度
方法一:函数递归
方法二:计数器
#include<stdio.h>
int main()
{
char ch[] = "mettri";//[m][e][t][t][r][i][\0]//计数不计[\0]
int my_strlen(char*);
printf("%d\n", my_strlen(ch));//数组名-数组首元素地址
return 0;
}
int my_strlen(char* str)
{
int c = 0;
for (; *str != '\0'; str++)
{
c++;
}
return c;
}
方法三:指针运算
#include<stdio.h>
int main()
{
char ch[] = "mettri";//[m][e][t][t][r][i][\0]
int my_strlen(char*);
printf("%d\n", my_strlen(ch));//数组名-数组首元素地址
return 0;
}
int my_strlen(char* str)
{
char* start = str;
for (; *str != '\0'; str++);
return str - start;
}
指针和数组
数组名是数组首元素地址
#include<stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int* p = arr;
//通过指针遍历数组
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", *(p + i)); //打印数组所有元素
// *(p + i) <==> arr[i]
}
return 0;
}
二级指针
指针变量也是变量,是变量就有地址
二级指针--存放指针变量地址的指针
#include<stdio.h>
int main()
{
int a = 6;
int* pa = &a; //pa--指针变量--一级指针
int** ppa = &pa; //ppa--二级指针
//解引用二级指针 //*ppa <==> pa //**ppa <==> a
printf("%d\n", **ppa); //输出 6
return 0;
}
指针数组
指针数组--存放指针的数组
int main()
{
int* parr[5]; //存放整型指针的数组-parr
char* pch[6]; //存放字符型指针的数组-pch
return 0;
}