目录
1 内存和地址
计算机CPU处理数据时,需要的数据从内存中读取,处理后也会放入内存中。为了高效管理内存空间,将内存划分成一个个的内存单元,每个内存单元的大小取一个字节,即8个比特位,每个比特位可以储存一个2进制的1或0。如:0X00000001 前面0X表示16进制
每个内存单元都有新编号,便于查找。C语言中地址的新名称:指针。
内存单元的编号==地址==指针
2 指针变量和地址
取地址操作符& 解引用操作符*
#include<stdio.h>
int main()
{
int a = 10;
int *pa = &a;//取出a的地址并存放在pa中
*pa=8;
printf("%d",a);//输出8
return 0;
}
2.1 指针变量
通过取地址操作符&取出的地址是数值,为了方便后期使用,我们将地址值存放在指针变量中。上述例子中指针变量就是pa,pa是变量,且存放a的地址,所以叫指针变量。
int *pa = &a;
*pa = 0;
*说明pa是指针变量,前面的int说明pa是指向整型(int)的类型对象。a的类型为int,pa的类型为int *。
*pa的意思是通过pa中存放的地址,找到指向的空间,*pa其实就是a变量。
指针变量有int */char */short */double *等类型。
2.2 指针变量的大小
#include<stdio.h>
int main()
{
printf("%zd\n",sizeof(char *));//输出4/8
printf("%zd\n",sizeof(int *));//输出4/8
printf("%zd\n",sizeof(short *));//输出4/8
printf("%zd\n",sizeof(double *));//输出4/8
return 0;
}
32位平台下地址是32个bit位,指针变量大小是4个字节。
64位平台下地址是64个bit位,指针变量大小是8个字节。
VS_2022中, X86环境下是32个bit位,X64是64个bit位。
指针变量的大小与类型无关,在相同的平台下,指针变量大小相同。
3 指针变量类型的意义
3.1 指针的解引用
指针的类型决定了对指针解引用的时候会获得多大权限 (一次能操作多少字节)。
如:char*的指针解引用只能一个字节,int*的可以访问四个字节。
3.2 指针+-整数
#include<stdio.h>
int main()
{
int n = 10;
char *pc = (char*)&n;
int *pi = &n;
printf("%p\n",&n);// 00AFF974
printf("%p\n",pc);// 00AFF974
printf("%p\n",pc+1);// 00AFF975
printf("%p\n",pi);// 00AFF974
printf("%p\n",pi+1);// 00AFF978
return 0;
}
&n、pc、pi都表示n的地址,pc是char*型,pi是int*型,所以pc+1增加一个字节,地址+1,pi+1增加4个字节,地址+4。
指针类型决定了指针向前或向后走一步有多少距离。
3.3 void*指针
void*类型,无具体类型的指针(或者叫泛型指针),可以接受任意类型地址。但不能直接进行指针的+-整数和解引用的运算。
1 int a =10;
2 int *p1 = &a;
3 char *p2 = &a; //void* p2=&a;
将int类型的变量的地址赋值给char*类型的指针变量(int型a的地址赋值给char* pa),类型不兼容,编译器会给警告,使用void*类型就不会有问题。 (不能*p2,void*类型指针不可以解引用)
4 const修饰指针
4.1 const修饰变量
变量是可以修改的,要想使其不能修改,需加上const。
#include<stdio.h>
int main()
{
int m = 0;
m = 20;//m从0变成20
const int n = 10;//使用const,n不可改变
n = 20;//err,程序不运行
printf("%d %d",m,n);//20 10
return 0;
}
const int n = 10,n本质还是变量,只是无法修改。const修饰变量a时,a叫常变量。
此时n无法修改,但如果使用指针修改n,还是能改变n的值。
1 const int n =10;
2 int* p = &n;
3 *p = 20;
4.2 const修饰指针变量
const修饰指针变量,两种形式。
1 int const * p;//const放在*的左边做修饰(或const int * p)*p不可变
2 int * const p;//const放在*的右边做修饰 p不可变
//int const * const p *p,p都不可变
const放在*左边,修饰的是指针指向的内容,指针指向的内容不能通过指针改变。但指针本身的内容可以变。
const放在*右边,修饰的是指针变量本身,指针变量的内容不能修改,但是指针指向的内容可以用指针来改变。
5 指针运算
三种:
指针+-整数
指针-指针
指针的关系运算
5.1 指针+-整数
数组在内存中连续存放,只要知道第一个元素的地址,就可以找到后面所有元素。
#include<stdio.h>
int main()
{
int arr[10]={1,2,3,4,5,6,7,8,9,10};
int* p = &arr[0];
int i = 0;
int sz = sizeof(arr)/sizeof(arr[0]);
for(i = 0; i < sz;i++){
printf("%d ",*(p+i));//没学指针前,此处填arr[i]
}
return 0;
}
p中存放第一个元素的地址,*p表示第一个元素,*(p+i)表示后续元素。
5.2 指针-指针
指针-指针的绝对值是指针和指针之间元素的个数。计算前提要求两个指针指向同一个空间,否则不连续,无法计算。
#include<stdio.h>
#include<string.h>
size_t my_strlen(char *p)
{
char* start = p;
char* end = p;
while(*end != '\0'){
end++;
}
return end-start;
}
int main()
{
char arr[]="abcdef";
size_t len = my_strlen(arr);
printf("%zd\n",len);//6
return 0;
}
指针+指针无意义。
相当于日期+-天数,日期-日期计算天数,而日期+日期无意义 。
5.3 指针的关系运算
指针的大小比较。
#include<stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int* p = &arr[0];
int sz = sizeof(arr) / sizeof(arr[0]);//10
while (p < arr + sz)
{
printf("%d ", *p);
p++;
}
return 0;
}
6 野指针
野指针产生原因:指针未初始化,指针越界访问,指针指向的空间释放。
int *p;//未初始化,默认随机值
int arr[10]={0};
int i = 0; int * p=&arr[0];
for(i = 0;i<=11;i++){
*(p++) = i;//指针指向的范围超出数组arr的范围时,p就是野指针
}
n是局部变量,将n的地址传给p时,p指向的空间释放