文章目录
指针的大小说明
指针存放的内容是什么?其大小取决什么?
指针在内存中存储的是一个内存地址,因为指针要能够指向内存地址里面的每个地址,而内存地址的长度取决于底层计算机的寻址能力(MAR的位数,存储单元的个数)。
不同位数计算机指针大小
在32位系统中,底层计算机的寻址空间为2的32次方,为了能访问到其中的每个地址,所以指针占用4个字节(32位)(因为一个字节等于八位);同理,在64位系统中占用8个字节(64位)。
指针常量和常量指针
先说结论:
指针常量是指一个指针,它指向的内存地址是固定的,不可更改。也就是说,指针常量指向的值是常量,不能通过该指针修改该值。但是指针本身的值(指向的地址)可以改变。
常量指针,指向常量的指针。该指针指向一个常量,常量的值不可变,不可以通过该指针修改其值,但是该指针可以指向其他常量。
常量指针
const int value = 100;
const int * pValue = &value;
*pValue = 200;// error 这个是错误的 不能修改一个常量的值 因为该指针指向一个常数
pValue = 200;// 该条语句是成功的
指针常量
int value = 100;
int*const pValue = &value;
pValue = 0x00; // 不被允许,因为是个常量指针
*pValue =200;// OK
指针变量的算数操作
示例代码:
int * pNumber = NULL;
pNumber = 0x0;
++pNumber;//0x4
pNumber + 2; //0x0c
- 指针变量的算数运算地址增加的长度和数据类型有关,示例中指针指向一个int类型,一个int型数据占4个字节,现在计算机一般都是以字节为单位进行编码的,即代表一个地址单位代表一个字节,则++pNumber之后,pNumber指向的地址会向后移动四个字节。pNumber+2继续向后移动八个字节。
- 若是char类型,++操作只会移动一个字节,以此类推double类型会移动8个字节。
- 这里不要和指针的大小弄混,指针变量也是个变量,存储的是地址。算数操作是对存储的地址值进行操作
指针和数组
数组是存储若干相同数据类型元素且地址连续的集合,数组也是有地址的,数组名就是该数组的首地址,数据名可以看做是一个特殊的常量指针,我们可以通过指针的偏移(++,–)对数组进行访问,示例如下:
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int *pArr = arr; // 这里不需要使用&数组名就是首地址
pArr[5] = 10; // 第一种访问方式
*(pArr+5) = 20; // 第二种访问方式
二级指针(指向指针的指针)
int a = 10;
// 一级指针是一个*
int* p = &a;// 指针p保存了a的地址
// 二级指针是二个*
int** pp = &p;// 指针pp 保存了p的地址
// 利用pp和p访问a
// *值取指针保存地址的值
printf("pp = %d,p = %d", **pp, *p);
一级指针:
指针变量p的类型为int* ,所指向的类型为int, 指针变量p指向了int类型a的内存地址
二级指针:
指针变量pp的类型为int**, 所指向的类型为int*, 指针变量p的类型为int*,所以pp指向p的内存地址,即pp保存的是p的首地址,*pp访问到的是p所储存的值,**p访问到的是a的值。
指针数组(保存指针的数组)
顾名思义,数组里面的每个元素都是一个指针类型的变量
// 声明指针数组
// 数据类型* 变量名[长度];
int* p1[10];
int a1 = 0, a2 = 0, a3 = 0;
p1[0] = &a1;
p1[1] = &a2;
p1[2] = &a3;
*(p1[0]) = 10;
*(p1[1]) = 20;
*(p1[2]) = 30;
printf("%d %d %d\n", a1, a2, a3);
数组指针(指向数组的指针)
我也没弄懂这个东西要干嘛,感觉没有什么实际的作用
// 数组指针
// 数据类型 (*变量名)[数组长度];
// 该数组指针指向一维数组
int(*p)[10];
int a[10];
// 数组指针的赋值
// 变量名 = 数组的地址
p = a;
// 数组指针的使用
//(*变量名)[数组长度] = 值
(*p)[0] = 10;
函数指针(指向函数的指针)
// 函数指针的声明
// 数据类型 (*变量名)(参数列表);
// 函数名 就是函数的首地址,函数名的作用,只是给人类识别用的(在汇报层面绘转换为二进制[地址])
void Print1()
{
printf("Hello World\n");
}
void Print2()
{
printf("Hello World2\n");
}
int main()
{
void (*p)();
// 只要函数的参数和返回值相同就可以直接调用和赋值
p = Print1;
p();
p = Print2;
p();
}
万能指针void *
void *指针可以指向任意变量的内存空间:
void *p = NULL;
int a = 10;
p = (void *)&a; //指向变量时,最好转换为void *
//使用指针变量指向的内存时,转换为int *
*( (int *)p ) = 11;
printf("a = %d\n", a);
以下是一些C语言中返回类型为void*的常见函数:
- malloc:动态分配内存,并返回指向分配内存块的指针。
void* malloc(size_t size);
- calloc:动态分配内存,并初始化为零,并返回指向分配内存块的指针。
void* calloc(size_t num, size_t size);
- realloc:重新分配先前分配的内存块的大小,并返回指向重新分配后内存块的指针。
void* realloc(void* ptr, size_t size);
- memset:将一块内存区域的内容设置为指定的值,并返回指向该内存区域的指针。
void* memset(void* ptr, int value, size_t num);