大家好我是沐曦希
内存–》内存的单元(1byte字节)–》编号–》地址–》指针
所以指针就是一个地址(编号)而已。
口头语中说的指针一般指:指针变量。指针变量就是一个变量而已,就是一块内存空间,指针变量用来存放地址。
指针变量在x32平台下大小为4个字节,在x64平台下大小为8个字节。
指针运算包括:
1.加减正数
2.指针-指针
3.指针的关系运算
指针也就是内存地址,指针变量是用来存放内存地址的变量,在同一CPU构架下,不同类型的指针变量所占用的存储单元长度是相同的,而存放数据的变量因数据的类型不同,所占用的存储空间长度也不同。有了指针以后,不仅可以对数据本身,也可以对存储数据的变量地址进行操作。
在 C/C++语言中,指针一般被认为是指针变量,指针变量的内容存储的是其指向的对象的首地址,指向的对象可以是变量(指针变量也是变量),数组,函数等占据存储空间的实体。
int a = 10;
int* pa = &a;//pa是指针变量,int*是指针变量pa的类型
//*说明pa是指针变量,int说明指针变量pa所指向的变量的类型
*pa = 20;//*pa解引用操作
printf("%d\n",a);//20
char ch = 'w';
char* pc = &ch;//字符指针
float a = 3.14f;
float* pf = &a;//浮点数指针
1.指针变量在进行加减整数运算时候,指针变量类型决定指针变量跳过几个字节(步长)。
2.指针变量进行解引用操作的时候,指针变量的类型决定了指针变量一次访问多少个字符(权限)。
指针数组:本质上就是数组,数组中存放的是指针(地址)。
int* pa = NULL;//指针变量要初始化,否则为野指针
int* pb = NULL;
int* pc = NULL;
int* pd = NULL;
int* arr[4] = {pa,pb,pc,pd};//指针数组
1.数组名在大部分情况下表示:首元素地址。
但有两个例外,下面两个数组名表示整个数组:
1.sizeof(数组名);//求的是整个数组在空间中所占内存的大小
//数组名单独包括在sizeof内
2.&数组名//取出的是整个数组的地址
#include
int main()
{
int arr[3] = { 1,2,3 };
printf("%d\n", sizeof(arr));//12
printf("%d\n", sizeof(&arr));//4或者8//地址的大小为4或者8,x32是4,x64是8
}
函数也是有地址,那么可以用指针变量来存储函数的地址,方便以后的函数调用。
#include
int Add(int x, int y)
{
return x + y;
}
int main()
{
int (*pa)(int, int) = &Add;
//函数的地址存放在函数的指针变量中
int (*pb)(int, int) = Add;
int ret = (*pa)(2, 3);
int sum = pb(2, 3);
printf("%p\n", &Add);
printf("%p\n", pa);
printf("%p\n", pb);
printf("%d\n", ret);
printf("%d\n", sum);
return 0;
}
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
函数指针数组指:本质上是数组,用于存放函数指针的数组。
int (*pf)(int , int ) = Add;
int (*pfArr[4])(int ,int );//int(*)(int ,int )是函数指针数组的类型
pfArr数组的每个元素的类型是:int(*)(int ,int );
pfArr数组可以存放四个类型为int(*)(int ,int )的函数指针。
#include
int int_cmp(const void* p1, const void* p2)
{
return (*(int*)p1 - *(int*)p2);
}
void _swap(void* p1, void* p2, int size)
{
int i = 0;
for (i = 0; i < size; i++)
{
char tmp = *((char*)p1 + i);
*((char*)p1 + i) = *((char*)p2 + i);
*((char*)p2 + i) = tmp;
}
}
void bubble(void* base, int count, int size, int(*cmp)(void*, void*))
{
int i = 0;
int j = 0;
for (i = 0; i < count - 1; i++)
{
for (j = 0; j < count - i - 1; j++)
{
if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0)
{
_swap((char*)base + j * size, (char*)base + (j + 1) * size, size);
}
}
}
}
int main()
{
int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
//char *arr[] = {"aaaa","dddd","cccc","bbbb"};
int i = 0;
bubble(arr, sizeof(arr) / sizeof(arr[0]), sizeof(int), int_cmp);
for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
小沐所用的平台是x32环境下的
//一维数组
#include
int main()
{
int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(a));
printf("%d\n", sizeof(a + 0));
printf("%d\n", sizeof(*a));
printf("%d\n", sizeof(a + 1));
printf("%d\n", sizeof(a[1]));
printf("%d\n", sizeof(&a));
printf("%d\n", sizeof(*&a));
printf("%d\n", sizeof(&a + 1));
printf("%d\n", sizeof(&a[0]));
printf("%d\n", sizeof(&a[0] + 1));
return 0;
}
1.sizeof(数组名),此时数组名表示整个数组,计算的是整个数组的大小,单位是字节。故为16个字节
2.a+0 中的数组名a不是单独放在sizeof内部,又没有取地址符号,所以a就是首元地址,a+0还是首元素地址,地址的大小为4或者8个字节。故为4或者8个字节
3.*a 中的数组名a是数组首元素的地址,*a就是对首元素的地址解引用,找到的就是首元素,因为首元素的类型为int整型,所以首元素的大小就是4个字节。故为4个字节
4.a+1 中的a是数组首元素的地址,a+1是第二个元素的地址,sizeof(a+1)就是地址的大小4或者8。故为4或者8个字节。
5.a[1] 表示的是第二位元素,故sizeof(a[1])计算的是第二位元素所占内存的大小。故为4个字节
6.&a取出的数组的地址,数组的地址,也就是个地址,而地址的大小是4或者8。故为4或者8个字节。
7.*&a 中的&a的类型是int(*)[4],&a拿到的是数组名的地址,类型是 int(*)[4],是一种数组指针,数组指针解引用找到的是数组,即相当于*和&相互抵消,即*&a等价于a,即求sizeof(a),而a表示整个数组,计算的是整个数组的大小,单位是字节。故为16个字节。
8.&a+1 中的&a取出的是数组的地址,&a的数组指针类型是 int(*)[4],&a+1 是从数组a的地址向后跳过了一个(4个整型元素的)数组的大小,&a+1还是地址,是地址就是4/8字节。故为4或者8个字节。
9.&a[0] 中&a[0]就是第一个元素的地址,计算的是地址的大小。故为4或者8个字节。
10.&a[0]+1 中&a[0]+1是第二个元素的地址,大小是4/8个字节,&a[0]+1相当于&a[1]。故为4个字节。
//字符数组
#include
#include
int main()
{
char arr[] = { 'a','b','c','d','e','f' };
//6个元素
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr + 0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr + 1));
printf("%d\n", sizeof(&arr[0] + 1));
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr + 0));
//printf("%d\n", strlen(*arr));//error
//printf("%d\n", strlen(arr[1]));//error
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr + 1));
printf("%d\n", strlen(&arr[0] + 1));
return 0;
}
strlen求字符串长度,关注的是字符串中的‘\0’,计算的是’\0’之前出现的字符串的个数,是库函数,只针对字符串。
sizeof只关注占用内存空间的大小,不在乎内存中存放的是什么,是操作符。
1.sizeof(数组名),此时数组名表示整个数组,计算的是整个数组的大小,单位是字节。故为6个字节
2.arr+0 中arr + 0 是数组首元素的地址,地址的大小为4或者8。故为4或者8个字节。
3.*arr 中arr表示首元素的地址,*arr表示首元素,大小为1个字节,故为1个字节。
4.arr[1]表示第二位元素,大小为一个字节。
5.&arr取的是整个数组的地址,地址的大小为4或者8个字节。
6.&arr+1 就是跳过一个数组后的地址,地址的大小为4或者8个字节。
7.&arr[0]+1相当于arr[1],即表示第二位元素,大小为一个字节。
8.strlen(arr) 表示在‘\0’(0)之前的元素个数,所以为随机值
9.strlen(arr+0)相当于strlen(arr),故依然为随机值
10.strlen(arr)相当于strlen(‘a’),又相当于strlen(97),是一个野指针,故是错误的。
11.strlen(arr[1])相当于strlen(‘b’),又相当于strlen(98),是一个野指针,故是错误的。
12.strlen(&arr)取得是整个数组的地址,从首元素开始数,到’\0’结束,即随机值。
13.strlen(&arr+1)表示跳过一个类型为char()[6]的数组,故为随机值-6。
14.strlen(&arr[0]-1)表示从第二位元素开始数,到’\0’结束,即随机值-1.以上的随机值相等
#include
int main()
{
char arr[] = "abcdef";
//7个元素
//[a b c d e f \0]
printf("%d\n", sizeof(arr));//7
printf("%d\n", sizeof(arr + 0));//4/8
printf("%d\n", sizeof(*arr));//1
printf("%d\n", sizeof(arr[1]));//1
printf("%d\n", sizeof(&arr));//4/8
printf("%d\n", sizeof(&arr + 1));//4/8
printf("%d\n", sizeof(&arr[0] + 1));//4/8
printf("%d\n", strlen(arr));//6
printf("%d\n", strlen(arr + 0));//6
//printf("%d\n", strlen(*arr));//error
//printf("%d\n", strlen(arr[1]));//error
printf("%d\n", strlen(&arr));//6
printf("%d\n", strlen(&arr + 1));//随机值
printf("%d\n", strlen(&arr[0] + 1));5
return 0;
}
#include
int main()
{
char* p = "abcdef";
//7个元素
printf("%d\n", sizeof(p));//4/8
printf("%d\n", sizeof(p + 1));//4/8
printf("%d\n", sizeof(*p));//1
printf("%d\n", sizeof(p[0]));//1
printf("%d\n", sizeof(&p));//4/8
printf("%d\n", sizeof(&p + 1));//4/8
printf("%d\n", sizeof(&p[0] + 1));//4/8
printf("%d\n", strlen(p));//6
printf("%d\n", strlen(p + 1));//5
//printf("%d\n", strlen(*p));//error
//printf("%d\n", strlen(p[0]));//p[0]-->*(p+0)//error
printf("%d\n", strlen(&p));//随机值
printf("%d\n", strlen(&p + 1));//随机值
printf("%d\n", strlen(&p[0] + 1));//5
return 0;
}
#include
int main()
{
int a[3][4] = { 0 };
printf("%d\n", sizeof(a));//3*4*4=48
printf("%d\n", sizeof(a[0][0]));4
printf("%d\n", sizeof(a[0]));
//a[0]是第一行这个一维数组的数组名,单独放在sizeof内部,a[0]表示第一个整个这个一维数组
//sizeof(a[0])计算的就是第一行的大小
printf("%d\n", sizeof(a[0] + 1));
//a[0]并没有单独放在sizeof内部,也没取地址,a[0]就表示首元素的地址
//就是第一行这个一维数组的第一个元素的地址,a[0] + 1就是第一行第二个元素的地址
printf("%d\n", sizeof(*(a[0] + 1)));
//a[0] + 1就是第一行第二个元素的地址
//*(a[0] + 1))就是第一行第二个元素
printf("%d\n", sizeof(a + 1));
//a虽然是二维数组的地址,但是并没有单独放在sizeof内部,也没取地址
//a表示首元素的地址,二维数组的首元素是它的第一行,a就是第一行的地址
//a+1就是跳过第一行,表示第二行的地址
printf("%d\n", sizeof(*(a + 1)));
//*(a + 1)是对第二行地址的解引用,拿到的是第二行
//*(a+1)-->a[1]
//sizeof(*(a+1))-->sizeof(a[1])
printf("%d\n", sizeof(&a[0] + 1));
//&a[0] - 对第一行的数组名取地址,拿出的是第一行的地址
//&a[0]+1 - 得到的是第二行的地址
printf("%d\n", sizeof(*(&a[0] + 1)));
printf("%d\n", sizeof(*a));
//a表示首元素的地址,就是第一行的地址
//*a就是对第一行地址的解引用,拿到的就是第一行
printf("%d\n", sizeof(a[3]));
return 0;
}
数组名的意义:
- sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。
- &数组名,这里的数组名表示整个数组,取出的是整个数组的地址。
- 除此之外所有的数组名都表示首元素的地址。
友友们觉得不错的可以给个关注,点赞或者收藏哦!感谢各位友友们的支持。
你的❤️点赞是我创作的动力的源泉
你的✨收藏是我奋斗的方向
你的关注是对我最大的支持
你的✏️评论是我前进的明灯
创作不易,希望大佬你支持一下小沐吧