1.指针是什么
#include <stdio.h>
int main()
{
int a = 10;//a是整型变量,占用4个字节的变量,在内存中开辟一块空间
int* pa = &a;//这里我们对变量a,取出它的地址,可以使用&操作符
//a变量占用4个字节的空间,这里是将a的4个字节的第一个字节的地址存放在pa变量中
//pa就是一个指针变量,用来存放地址的
//本质上指针就是地址;
//口语说的指针,其实是指针变量,指针变量就是一个变量,指针变量是用来存放地址的一个变量
return 0;
}
2.指针和指针类型
2.1指针+-整数
#include<stdio.h> int main() { int n = 10; int* pa = &n; char* pc = (char*)&n; printf("%p\n", &n); printf("%p\n", pa); printf("%p\n", pa + 1); printf("%p\n", pc); printf("%p\n", pc + 1); //结论: // 指针的类型决定了指针+-1操作的时候,跳过了几个字节 //决定了指针的步长 //100 - 10进制 //0X64 - 16进制 //1100100 - 二进制 //144 - 8进制 return 0; }
2.2指针的解引用
//X86 - 32位的环境 - 4
//X64 - 64位的环境 - 8
#include<stdio.h>
int main()
{
char* pc = NULL;
int* pi = NULL;
short* ps = NULL;
long* pl = NULL;
float* pf = NULL;
double* pd = NULL;
//sizeof 的返回值是无符号的整型 - unsigned int
printf("%zu\n", sizeof(pc));//4
printf("%zu\n", sizeof(pi));//4
printf("%zu\n", sizeof(ps));//4
printf("%zu\n", sizeof(pl));//4
printf("%zu\n", sizeof(pf));//4
printf("%zu\n", sizeof(pd));//4
return 0;
}
#include<stdio.h>
int main()
{
int a = 0X11223344;
int* pa = &a;
*pa = 0;
printf("%x\n", a);//00000000
char* pc = (char*)&a;
*pc = 0;
printf("%x\n", a);//11223300
//结论:
//指针类型决定了指针在被解引用的时候访问了几个字节
//如果是int*的指针,解引用访问4个字节
//如果是char*的指针,解引用访问1个字节
//推广到其它类型
return 0;
}
#include<stdio.h> int main() { int a = 0; int* pi = &a;//pi解引用访问4个字节,pi+1是跳过4个字节 float* pf = &a;//pf解引用访问4个字节,pf+1是跳过4个字节 //int* 和float*是否能通用? //不能 //* pi=100; //* pf=100.0; return 0; }
3. 野指针
概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
3.1 野指针成因
//1. 指针未初始化
#include<stdio.h>
int main()
{
int* p;//p没有初始化,就意味着没有明确的指向
//p是一个局部的指针变量,局部变量不初始化的话,默认是随机值:0Xcccccccc
*p = 20;//非法访问内存了,这里的p就是一个野指针
return 0;
}
//2.越界访问 #include<stdio.h> int main() { int arr[10] = { 0 }; int* p = arr;//int* p = &arr[0] int i = 0; for (i = 0; i <= 10; i++)//当指针指向的范围超出数组arr的范围时,p就是野指针 { *p = i; p++; } return 0; }
3. 指针指向的空间释放
#include<stdio.h>
int* test()
{
int a = 10;//在局部变量开辟了一块空间,出了函数后就会返还空间给操作系统
return &a;
}
int main()
{
int*p = test();
printf("hehe\n");
printf("%d\n", *p);//随机值
return 0;
}
3.2 如何规避野指针
4. 指针运算
4.1 指针+-整数
#include<stdio.h> #define N_VALUES 5 int main() { float values[N_VALUES]; float* vp; //指针+-整数;指针的关系运算 for (vp = &values[0]; vp < &values[N_VALUES];) { *vp++ = 0; } return 0; }
#include<stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
//代码1
//for (i = 0; i < sz; i++)
//{
// arr[i] = 1;
// printf("%d ", *p);
//}
//代码2
//int* p = arr;
//for (i = 0; i < sz; i++)
//{
// *p = 1;
// printf("%d ", *p);
// p++;
//}
//代码3
//int* p = arr;
//for (i = 0; i < sz; i++)
//{
// *(p + i) = 1;
// printf("%d ", *p);
//}
//代码4
//int* p = arr;
//int* pend = arr + 9;
//while (p<=pend)
//{
// *p = 1;
// printf("%d ", *p);
// p++;
//}
return 0;
}
4.2 指针-指针
#inlcude<stdio.h> int main() { int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; char c[5]; //指针和指针相减的前提: //两个指针指向同一块空间 printf("%d\n", &arr[9] - &c[0]);//err // |指针-指针|的绝对值是指针和指针之间的元素个数 printf("%d\n", &arr[9] - &arr[0]);//9 return 0; }
#include<stdio.h>
int my_strlen(char* str)
{
char* start = str;
while (*str != '\0')
{
str++;
}
return str - start;
}
int main()
{
int len = my_strlen("abc");//求字符串长度
printf("%d\n", len);//3
return 0;
}
4.3 指针的关系运算
5. 指针和数组
#include<stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10};
int* p = arr;//数组名
printf("%d\n", arr[2]);
printf("%d\n", p[2]);//p[2] --> *(p+2)
//[] 是一个操作符 2和arr是两个操作数
printf("%d\n", 2[arr]);
printf("%d\n", arr[2]);
//arr[2] --> *(arr+2)-->*(2+arr)-->2[arr]
//arr[2] <==> *(arr+2) <==> *(p+2) <==> *(2+p) <==> *(2+arr) == 2[arr]
//2[arr] <==> *(2+arr)
return 0;
}
#include<stdio.h> int main() { int arr[10] = { 0 }; int* p = arr;//等价于int* p = &arr[0] printf("%p\n", arr);//数组名arr是数组首元素的地址 printf("%p\n", &arr[0]); int i = 0; for (i = 0; i < 10; i++) { printf("%p <==> %p\n", &arr[i], p + i);//地址相同 } for (i = 0; i < 10; i++) { printf("%d ", *(p + i)); } return 0; }
#include<stdio.h>
//代码1
//void test(int* p, int sz)
//{
//int i = 0;
//for (i = 0; i < sz; i++)
//{
//printf("%d ", *(p + i));
//}
//}
//代码2
void test(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);//arr[i]->*(arr+i)
}
}
int main()
{
int arr[10] = { 0 };
test(arr, 10);
return 0;
}
6. 二级指针
#include<stdio.h>
int main()
{
int a = 10;
int* pa = &a;//pa是一个指针变量,一级指针变量
//ppa就是一个二级指针变量
int ** ppa = &pa;//ppa也是个变量,&pa取出pa在内存中起始地址
//*pa = 20;
**ppa = 20;//*ppa通过对ppa中的地址进行解引用,这样找到的是pa,*ppa其实访问的就是pa
//**ppa先通过*ppa找到pa,然后对pa进行解引用操作:*pa,然后找到a
printf("%d\n", a);
int*** pppa = &ppa;
return 0;
}
7. 指针数组
//指针数组 - 数组 //存放指针的数组就是指针数组 #include<stdio.h> int main() { int a = 10; int b = 20; int c = 30; int* pa = &a; int* pb = &b; int* pc = &c; int arr[10];//整型数组 - 存放整型的数组就是整形数组 char ch[5];//字符数组 - 存放的是字符 int* parr[10] = {&a, &b, &c};//parr就是整形指针的数组 - 存放整型指针的数组 int i = 0; for (i = 0; i < 3; i++) { printf("%d ", *(parr[i]));//10 20 30 } return 0; }
#include<stdio.h> int main() { int arr1[4] = { 1,2,3,4 }; int arr2[4] = { 2,3,4,5 }; int arr3[4] = { 3,4,5,6 }; int* parr[3] = { arr1, arr2, arr3 }; int i = 0; for (i = 0; i < 3; i++) { int j = 0; for (j = 0; j < 4; j++) { printf("%d ", parr[i][j]); } printf("\n"); } return 0; }