1.为什么需要指针
第一,指针的使用使得不同区域的代码可以轻易的共享内存数据。当然你也可以通过数据的复制达到相同的效果,但是这样往往效率不太好,因为诸如结构体等大型数据,占用的字节数多,复制很消耗性能。但使用指针就可以很好的避免这个问题,因为任何类型的指针占用的字节数都是一样的(根据平台不同,有4字节或者8字节或者其他可能)。
第二,指针使得一些复杂的链接性的数据结构的构建成为可能,比如链表,链式二叉树等等。
第三,有些操作必须使用指针。如操作申请的堆内存。
2.指针概念
指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址。就像其他变量或常量一样,您必须在使用指针存储其他变量地址之前,对其进行声明。指针变量声明的一般形式为:
type *var_name;
每一个变量都有一个内存位置,每一个内存位置都定义了可使用连字号(&)运算符访问的地址,它表示了在内存中的一个地址。指针是程序数据在内存中的地址,而指针变量是用来保存这些地址的变量。
3.程序变量在内存中存储原理
我们编写程序变量和计算机物理内存是一一对应关系,其关系如下,通常将物理内存进行映射成虚拟内存,程序员通过操纵虚拟内存来操作变量。虚拟内存是一个较大的线性表,通常说的4G内存虚拟存储器的模型,它一共有4x1024x1024x1024 个字节,那么它的虚拟地址范围就是 0 ~ 4x1024x1024x1024-1(0x00000000-0xFFFFFFF) ,每个字节8个二进制组成。
在内存中,每个字节都有都有一个唯一的编号(好比一栋楼里面的每个房间的门牌号),在程序中使用的变量,常量,甚至数函数等数据,当他们被载入到内存中后,都有自己唯一的一个编号,这个编号就是这个数据的地址。指针就是这样形成的。
#include<stdio.h>
int main()
{
int a;
char s[10];
int *p = &a;
char *pb = s;
printf("a 变量的地址是%p\n",&a);
printf("a 变量的地址是%p\n", p);
printf("s[10] 变量的地址是%p\n", &s);
printf("s[10]变量的地址是%p\n", pb);
return 0;
}
指针实质上存储的是内存上一个编号,也即是某变量在内存中地址,其值是一个整数,通常用16进制进行标识。
4.指针变量
用来保存 指针(地址) 的变量,就是指针变量。如果指针变量p保存了变量 var的地址,则就说:p指向了变量var,也可以说p指向了var所在的内存块,任何类型指针变量的空间大小都是4个字节 。
5.指针的定义使用
定义变量时,在变量名 前 写一个 * 星号,这个变量就变成了对应变量类型的指针变量。必要时要加( ) 来避免优先级的问题,比如函数指针。
#include<stdio.h>
int main()
{
//语法:变量类型 * 指针变量名称 int* p,同时定义两个指针,则需要在每个变量前加*int *p1,*p2
int a; //int类型变量 a
int* p; //int* 变量p
int arr[3]; //arr是包含3个int元素的数组
int(*parr)[3]; //parr是一个指向【包含3个int元素的数组】的指针变量
//-----------------各种类型的指针------------------------------
int* p_int; //指向int类型变量的指针
double* p_double; //指向double类型变量的指针
struct Student *p_struct; //结构体类型的指针
int(*p_func)(int, int); //指向返回类型为int,有2个int形参的函数的指针
int(*p_arr)[3]; //指向含有3个int元素的数组的指针
int** p_pointer; //指向 一个整形变量指针的指针
return 0;
}
特殊的情况,他们并不一定需要使用&取地址:
- 数组名的值就是这个数组的第一个元素的地址。
- 函数名的值就是这个函数的地址。
- 字符串字面值常量作为右值时,就是这个字符串对应的字符数组的名称,也就是这个字符串在内存中的地址。
6.解析地址(求变量的值或者赋值)
对一个指针解地址,就可以取到这个内存数据,解地址 的写法,就是在指针的前面加一个*号,然后就可以对指向的内存地址上内容进行读或写。
#include<stdio.h>
int main()
{
int n = 100;
int*p = &n;
*p = 20; //通过指针修改指向的内存数据
printf("n = %d\n", *p); //通过指针读取指向的内存数据
printf("n= %d\n", n);
return 0;
}
7.空指针
在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个 NULL 值是一个良好的编程习惯。赋为 NULL 值的指针被称为空指针。NULL 指针是一个定义在标准库中的值为零的常量。
#include <stdio.h>
int main()
{
int *ptr = NULL;
printf("ptr 的地址是 %p\n", ptr);
return 0;
}
8.指针注意事项
(1)指针变量赋值:指针变量不可以直接使用整数变量或者常量赋值。
#include <stdio.h>
int main()
{
int *p = 100; //错误,不能用常量赋值
int i = 100;
*p = i; //错误:p是指针变量,i是整型变量
return 0;
}
(2)不同类型指针变量之间不能赋值(强制转化除外)
#include <stdio.h>
int main()
{
int i = 10;
int *p = &i;//正确:指针类型和变量类型一致
char *pb = p;//错误,类型不同
return 0;
}