目录
1. 指针是什么
指针理解的2个要点:
1. 指针是内存中一个最小单元的编号,也就是地址
2. 平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量
总结:指针就是地址,口语中说的指针通常指的是指针变量。
#include<stdio.h>
int main()
{
int a = 10;
int* pa = &a; //pa是指针变量
printf("%d\n", sizeof(pa)); // 4
// printf("%p\n", &a);
// 00000000 00000000 00000000 00001010
// 00 00 00 0a
return 0;
}
我们可以通过&(取地址操作符)取出变量的内存其实地址,把地址可以存放到一个变量中,这个 变量就是指针变量
在32位的机器上,地址是32个0或者1组成二进制序列,那地址就得用4个字节的空间来存储,所以 一个指针变量的大小就应该是4个字节。
那如果在64位机器上,如果有64个地址线,那一个指针变量的大小是8个字节,才能存放一个地 址。
总结: 指针是用来存放地址的,地址是唯一标示一块地址空间的。 指针的大小在32位平台是4个字节,在64位平台是8个字节。
2. 指针和指针类型
#include<stdio.h>
int main()
{
char* pc;
int* pa;
double* pd;
printf("%d\n",sizeof(pc)); // 4
printf("%d\n", sizeof(pa)); // 4
printf("%d\n", sizeof(pd)); // 4
return 0;
}
指针作用1:指针类型决定了在解引用时能访问几个字节(指针的权限)
#include<stdio.h>
int main()
{
int a = 0x11223344;
int* pa = &a;
*pa = 0;
char* pc = &a;
*pc = 0;
// 指针类型决定了在解引用的时候以此能访问几个字节(指针的权限)
// int* --> 4
// char* --> 1
// double* --> 8
return 0;
}
指针作用2:指针类型决定了//指针作用2:指针类型决定了指针向前或者向后走一步,走多大距离(单位是字节)
#include<stdio.h>
int main()
{
int a = 10;
int* pa = &a;
char* pc = &a;
printf("%p\n", pa); //001EFE54
printf("%p\n", pa + 1); //001EFE58
printf("%p\n", pc); //001EFE54
printf("%p\n", pc + 1); //001EFE55
return 0;
}
例如:
创建一个整型数组,10个元素
1:初始化数组的内容是1-10
2:打印数组
#include<stdio.h>
int main()
{
int arr[10] = { 0 };
int* p = arr;
int i = 0;
for (i = 0; i < 10; i++)
{
*(p + i) = i+1;
}
// 倒着打印
int* q = &arr[9];
for (i = 0; i < 10; i++)
{
printf("%d ", *q); // 10 9 8 7 6 5 4 3 2 1
q--;
}
return 0;
}
3. 野指针
概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
成因:
#include<stdio.h>
int main()
{
/*int a;
printf("%d\n", a);*/
//未初始化
//int* p; //野指针
//*p = 20;
//越界访问
int arr[10] = { 0 };
int* p = arr;
int i = 0;
for (i = 0; i <= 10; i++)
{
*p = i;
p++;
}
return 0;
}
如何规避野指针?如下:
1. 指针初始化
2. 小心指针越界
3. 指针指向空间释放即使置NULL
4. 避免返回局部变量的地址 5. 指针使用之前检查有效性
#include<stdio.h>
int* test()
{
int a = 100;
return &a;
}
int main()
{
int* p = test();
printf("%d\n", *p); // 100
return 0;
}
// 指针指向空间及时放置NULL
#include<stdio.h>
int main()
{
int* p = NULL;
if (p != NULL)
{
*p = 100;
}
int arr[10] = { 0 };
int* q = arr;
q = NULL;
return 0;
}
4. 指针运算
#include<stdio.h>
int main()
{
int arr[10] = { 0 };
int* p = arr;
int i = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
for (i = 0; i < sz; i++)
{
*(p + i) = i + 1;
}
for (i = 0; i < sz; i++)
{
printf("%d ", *(p + i)); // 1 2 3 4 5 6 7 8 9 10
}
return 0;
}
倒着打印:
#include<stdio.h>
int main()
{
int arr[10] = { 0 };
int* p = arr;
int i = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
for (i = 0; i < sz; i++)
{
*(p + i) = i + 1;
}
int* q = &arr[sz - 1];
//int* q = arr + sz - 1;
for (i = 0; i < sz; i++)
{
printf("%d ", *q); // 10 9 8 7 6 5 4 3 2 1
q--;
}
return 0;
}
指针减指针
#include<stdio.h>
int main()
{
int a[10] = { 0 };
printf("%d\n", &a[9] - &a[0]); // 9
printf("%d\n", &a[0] - &a[9]); // -9
return 0;
}
//相减的前提是两块指针指向同一块空间
#include<stdio.h>
int main()
{
int a = 10;
char c = 'w';
&a - &c; // 编译器报错,不能不同类型指针相加减
return 0;
}
求字符串长度(拓展)指针-指针
#include<stdio.h>
#include<string.h>
int my_strlen(char* s)
{
char* start = s;
while (*s != '\0')
{
s++;
}
return s - start;
}
int main()
{
char arr[] = "abc";
int len = my_strlen(arr);
printf("%d\n", len); // 3
return 0;
}
5. 指针和数组
#include<stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int* p = arr;
int i = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
/*for (i = 0; i < 10; i++)
{
printf("%p==%p\n", p + i, &arr[i]);
}*/
for (i = 0; i < 10; i++)
{
printf("%d ", p[i]); // 1 2 3 4 5 6 7 8 9 10
}
return 0;
}
6. 二级指针
指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪里? 这就是 二级指针
#include<stdio.h>
int main()
{
int a = 10;
int* pa = &a;
int** ppa = &pa; //ppa就是一个二级指针
int*** pppa = &ppa;//pppa就是一个三级指针
//***pppa = 20;
*pa = 20;
printf("%d\n", a);
return 0;
}
7. 指针数组
#include<stdio.h>
int main()
{
int arr[10]; //整型数组,存放整形的数组
char ch[5]; //字符数组,存放字符的数组
//指针数组,存放指针的数组
int a = 10;
int b = 20;
int c = 30;
int* arr2[5] = { &a,&b,&c }; //存放整形指针的数组
int i = 0;
for (i = 0; i < 5; i++)
{
printf("%d ", *(arr2[i])); // 10 20 30
}
return 0;
}
指针数组是指针还是数组?
答案:是数组。是存放指针的数组。
数组我们已经知道整形数组,字符数组。
那指针数组是怎样的?
arr3是一个数组,有五个元素,每个元素是一个整形指针。