指针
指针变量的定义和使用:
- 指针也是一种数据类型,指针变量也是一种变量
- 指针变量指向谁,就把谁的地址赋值给指针变量
- “*”操作符操作的是指针变量指向的内存空间
#include <stdio.h>
int main()
{
int a = 0;
char b = 100;
printf("%p, %p\n", &a, &b); //打印a, b的地址
//int *代表是一种数据类型,int*指针类型,p才是变量名
//定义了一个指针类型的变量,可以指向一个int类型变量的地址
int *p;
p = &a;//将a的地址赋值给变量p,p也是一个变量,值是一个内存地址编号
printf("%d\n", *p);//p指向了a的地址,*p就是a的值
char *p1 = &b;
printf("%c\n", *p1);//*p1指向了b的地址,*p1就是b的值
return 0;
}
008FF87C, 008FF873
0
d
请按任意键继续. . .
注意
&可以取得一个变量在内存中的地址。但是,不能取寄存器变量,因为寄存器变量不在内存里,而在CPU里面,所以是没有地址的。
指针的大小:
- 使用sizeof()测量指针的大小,得到的总是:4或8
- sizeof()测的是指针变量指向存储地址的大小
- 在32位平台,所有的指针(地址)都是32位(4字节)
- 在64位平台,所有的指针(地址)都是64位(8字节)
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main() {
int *p1;
char *p2;
float *p3;
int **p11;
char **p22;
float **p33;
printf("sizeof(p1) = %d\n", sizeof(p1));
printf("sizeof(p2) = %d\n", sizeof(p2));
printf("sizeof(p3) = %d\n", sizeof(p3));
printf("sizeof(p11) = %d\n", sizeof(p11));
printf("sizeof(p22) = %d\n", sizeof(p22));
printf("sizeof(p33) = %d\n", sizeof(p33));
}
X64
sizeof(p1) = 8
sizeof(p2) = 8
sizeof(p3) = 8
sizeof(p11) = 8
sizeof(p22) = 8
sizeof(p33) = 8
请按任意键继续. . .
X86
sizeof(p1) = 4
sizeof(p2) = 4
sizeof(p3) = 4
sizeof(p11) = 4
sizeof(p22) = 4
sizeof(p33) = 4
请按任意键继续. . .
野指针和空指针:
野指针:不同于定义的a,其在程序本身没有具体地址。它指向的是一个未知的内存空间(操作系统不允许指针指向的内存区域)。所以,野指针不会直接引发错误,操作野指针指向的内存区域才会出问题。
//野指针
//指向内存编号为100的内存地址
//0-255都是系统保留的,不能读、写
//野指针(不同于a,在程序本身没有)指向的是一个未知的内存空间,在读写的时候可能出错也可能不出错
int a = 100;
int *p;
p = a; //把a的值赋值给指针变量p,p为野指针, ok,不会有问题,但没有意义
p = 0x12345678; //给指针变量p赋值,p为野指针, ok,不会有问题,但没有意义
*p = 1000; //操作野指针指向未知区域,内存出问题,err
万能指针以及指针指向数组某个元素:
是使用 void * p来创建指针变量
int a = 10;
//万能指针
void *p = NULL;
p = &a;
//对于万能指针赋值需要对应原来值的变量类型(强转)
*(int *)p = 100;
printf("%d\n", a);
printf("%d\n", *(int *)p); //需要告诉指针读取多少个字节大小(这里int为四个字节大小)
指针指向数组某个元素并输出
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main() {
int arr[10] = { 0 }; //初始化数组全为0
void* p = &arr; //创建万能指针
*(int *)p = 100; //将arr[0]赋值为100(表示的是初始地址)
*((int *)p + 1) = 200; //此时p已经被转换成int类型,故进行+1操作表示是下一个元素位置(相当于地址+4)
for (int i = 0; i < 10; i++)
{
printf("%d\n", arr[i]);
}
}
100
200
0
0
0
0
0
0
0
0
请按任意键继续. . .
const修饰指针
const修饰什么类型的变量,其变量就无法直接更改。简而言之,就是const修饰的变量被锁死,无法进行更改。
const修饰内容以及结果:
const修饰内容 | 结果 |
const int a = 10; //a = 100; int *p = &a; *p = 100; |
可以通过一级指针修改常量的值 |
const int* p; p = &a; p = &b; //*p = 100; |
const修饰指针类型 可以修改指针指向的地址 |
int * const p = &a; *p = 100; //p = &b; | const修饰指针变量 可以修改指针指向地址的值 |
const int * const p = &a; //p = &b; //*p = b; | Const修饰指针数据类型 Const修饰指针变量 都不可以修改 |
代码如下:(具体看代码注释)
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
//这样安全,别人找不到所存的地址
#define MAX 100
int main401() {
//这种方式不安全,可以通过指针修改
//1、通过一级指针修改const修饰的常量
const int a = 10;
//a = 100;
int *p = &a;
*p = 100;
printf("a的值%d\n", a);
printf("*p的值%d\n", *p);
return 0;
}
int main402() {
//2、const能改变指针变量对应的地址,但是不能直接修改指向内存地址对应的元素
int a = 10;
int b = 30;
//如果const修饰指针类型,则不能修改指针变量指向的内存地址的值,但是可以改变其对应的地址
const int* p;
p = &a;
p = &b; //改变其对应的地址
/* *p = 100; 左值指定const对象 */
printf("%d", a);
return 0;
}
int main403() {
//const 能改变指针变量对应的地址的值,但是不能修改指针指向的地址
int a = 10;
int b = 20;
//const 修饰谁,则谁就无法改变,这里const修饰指针类型的p,p指向地址,所以地址无法改变
int * const p = &a;
*p = 100;
/* p = &b; 地址无法修改*/
printf("%d\n", *p);
return 0;
}
int main() {
//const 修饰指针类型也修饰指针变量,则指针指向的地址以及指针指向的值
int a = 10;
int b = 20;
const int * const p = &a;
/* 都会报错无法修改(二级指针可以修改)
p = &b;
*p = b;
*/
}