指针是什么:在计算机科学中,指针(pointer)是编程语言中的一个对象,利用地址,它的值直接指向存在电脑存储器中另一个地方的值。由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元。因此,将地址形象化的称为“指针”。意思是通过它能找到以它为地址的内存单元。

总结:指针是个变量,存放内存单元的地址(编号)。


在32位的机器上,地址是32个0或者1组成的二进制序列,那地址就得用4个字节的空间来存储,所以一个指针变量的大小就应该是4个字节。

那么在64位的机器上,有64个地址线,那一个指针变量的大小是8个字节,才能存放一个地址。

总结:指针是用来存放地址的,地址是唯一标示一块地址空间的。指针的大小在32位平台是4个字节,在64位平台是8个字节。


指针类型决定了指针进行解引用操作的时候,能够访问空间的大小

int* p; *p能够访问4个字节

char* p; *p能够访问1个字节

double* p; *p能够访问8个字节


#include <stdio.h>
int main()
{
int a = 0x11223344;
int* pa = &a;
char* pc = &a;
printf("%p\n", pa);
printf("%p\n", pa + 1); // int*类型向后多4个字节

printf("%p\n", pc);
printf("%p\n", pc + 1); // char*类型向后多1个字节
return 0;
}

总结:指针的类型决定了指针向前或者向后走一步有多大(步长)。


野指针

概念:野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)

成因:1、指针未初始化(局部的指针变量没有初始化,就会被初始化为随机值)

    2、指针越界访问

    3、指针指向的空间被释放

// 指针未初始化
// 实在不知道放什么的话就赋值NULL,int* p = NULL;
#include <stdio.h>
int main()
{
int a[10] = {0}; // 局部变量未初始化,里边默认放的是一个随机值
*p = 20; // 报错
return 0;
}


// 指针越界问题
#include <stdio.h>
int main()
{
int a[10] = {0};
int i = 0;
int* p = a;
for(i = 0; i <= 12; i++) // 当指针指向的范围超出了数组a的范围时,p就是野指针
{
// *p = i;
// p++;
*p++ = i; //先解引用,再加加,等同于上面的两句语法
}
return 0;
}


// 指针指向的空间被释放
#include <stdio.h>
int* test()
{
int a = 10; // 局部变量,进入大括号时创建,出去的时候就销毁了
return &a;
}
int main()
{
int* p = test();
printf("%d\n", *p); // 非法访问
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]);
int* p = arr;
for(i = 0; i < sz; i++)
{
printf("%d ", *p);
// p++;
p += 2; // 返回13579
}
return 0;
}


指针 - 指针

#include <stdio.h>
int main()
{
int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
printf("%d\n", &arr[9] - &arr[0]); // 得到的是中间元素的个数,小地址-大地址 = 负数,绝对值为个数
return 0;
}

用指针 - 指针实现求字符串的长度

#include <stdio.h>
int my_strlen(char* str)
{
char* start = str;
char* end = str;
while(*end != '\0')
{
end++;
}
return end - start;
}
int main()
{
// strlen求字符串的长度

char arr[] = "bit";
int len = my_strlen(arr);
printf("%d\n", len);
return 0;
}


指针和数组

#include <stdio.h>
int main()
{
int arr[10] = { 0 };
printf("%p\n", arr); // 地址-首元素的地址
printf("%p\n", arr + 1); // +1多4个字节

printf("%p\n", arr[0]); // 和上面的结果一样
printf("%p\n", arr[0] + 1);

// &arr不是首元素的地址,而是表示整个数组的地址
printf("%p\n", &arr); // 表示整个数组的地址
printf("%p\n", &arr + 1); // 表示跳过一个数组,直接多40个字节

return 0;
}

指针能很好的访问数组

#include <stdio.h>
int main()
{
int arr[10] = { 0 };
int* p = arr;
int i = 0;
for(i = 0; i < 10; i++)
{
*(p + i) = i;
printf("%d", *(p + i));
}
return 0;
}


二级指针

#include <stdio.h>
int main()
{
int a = 10;
int* pa = &a;
int** ppa = &pa; // **pa就是二级指针
printf("%d\n", **ppa);
// int*** pppa = &ppa; // 三级指针,依次类推得到n级指针
return 0;
}


指针数组与数组指针

​指针数组是存放指针的数组

#include <stdio.h>
int main()
{
// 整型数组 - 存放整型
// 字符数组 - 存放字符
// 指针数组 - 存放指针
int a = 10;
int b = 20;
int c = 30;
int* arr[3] = {&a, &b, &c}; // 指针数组
int i = 0;
for(i = 0; i < 3; i++)
{
printf("%d ", *(arr[i]));
}
return 0;
}