深入理解指针(5)

news2024/9/23 13:28:05

在之前的深入理解指针(4)中我们学习了回调函数相关知识,并且学会了如何使用库函数qsort,以及模拟实现了qsort,接下来在本篇中将对srtlen和sizeof进行细致的讲解,并对相关的题型进行讲解,一起加油吧!!!

99e5d146bafd4617b021f1d3bf08dc1b.jpeg


1.strlen与sizeof的区别

1.sizeof

在之前学习操作符的时候就已经了解过了sizeof这个操作符,sizeof计算变量所占内存内存空间大小,单位是字节,例如当变量类型是整形时,变量大小和变量类型的大小都是一样的
 

#inculde <stdio.h>
int main()
{
int a = 10;
printf("%d\n", sizeof(a));
printf("%d\n", sizeof(int));
return 0;
}

例如以上代码打印结果都是4 


2.strlen

strlen是一个用来求字符串长度的函数,计算的是字符串\0之前的字符的个数
strlen 函数会从起始地址一直向后找 \0 字符,直到找到为止,所以可能存在越界查找

函数的原型如下:

size_t strlen(const char * str );
#include<string.h>
#include<stdoio.h>
int main()
{
 char arr1[]="abc";
 char arr2[]={'a','b','c'};
 printf("%d\n",strlen(arr1));
 printf("%d\n",strlen(arr2));

 return 0;
}

在以上代码中数组arr1中存放的是字符串,数组的末尾包含\0;而数组arr2中存放的是字符,数组的末尾不包含\0,因此当使用strlen函数时,当参数为arr1时,可以求出地址arr1到\0之前元素的个数为3,所以打印结果为3.  但当参数为arr2时,由于原arr2数组中无\0因此会一直向后直到找到\0为止,所以打印出结果为随机数


3.sizeof与strlen的区别 

sizeofstrlen
sizeof是操作符strlen是库函数,使⽤需要包含头⽂件 string.h
sizeof计算操作数所占内存的大小,单位是字节srtlen是求字符串(字符数组)⻓度的,统计的是 \0 之前字符的个数
不关注内存中存放什么数据关注内存中是否有 \0 ,如果没有 \0 ,就会持续往后找,可能
会越界

2.数组和指针笔试题解析

2.1 一维数组

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));

以上各代码输出结果及解析:
int a[ ] = {1,2,3,4};


printf("%d\n",sizeof(a));

数组名a单独放在sizeof中,a表示的是整个数组,计算的是整个数组的大小,单位是字节,又因为数组a中元素类型都为int大小为4字节,所以整个数组大小就为16字节,打印结果为16


printf("%d\n",sizeof(a+0));

数组名a不是单独放在sizeof内,所以a表示的是数组首元素的地址,所以sizeof求出的是数组首元素指针的大小,在32位环境下为4字节,在64位环境下位8字节,打印结果为4或者8


printf("%d\n",sizeof(*a));

数组名a不是单独放在sizeof内,在此a表示的是数组首元素的地址,所以对a解引用后得出的就是数组首元素,因为数组元素为int类型,所以求出结果为4,打印结果为4


printf("%d\n",sizeof(a+1));

在此a表示的是数组首元素的地址,在对指针a加一后表示的是数组的第二个元素的地址,所以sizeof求出的是数组首元素指针的大小,在32位环境下为4字节,在64位环境下位8字节,打印结果为4或者8


printf("%d\n",sizeof(a[1]));

在此a[1]表示的是数组的第一个元素1,因为数组元素为int类型,所以结果为4,打印结果为4


printf("%d\n",sizeof(&a));

取地址取出的是整个数组的地址,所以sizeof求出的是整个数组的指针大小,在32位环境下为4字节,在64位环境下位8字节,打印结果为4或者8


printf("%d\n",sizeof(*&a));

有两种角度分析以上代码:

1.在此次*可以与&消除后sizeof中就剩a,这里的a单独放在sizeof内,sizeof求出的是整个数组的大小,为16字节,打印结果为16

2.在此&a取出的是整个数组的地址,类型为int(*)[4],解引用&a后访问的就是整个数组,数组大小为16字节,打印结果为16


printf("%d\n",sizeof(&a+1));

首先&a取出的是整个数组的地址,之后&a+1后的步长就为sizeof(int(*)[4]),为16字节,所以&a+1表示的是跳过整个数组后那个位置的地址,sizeof(&a+1)求出的就是这个位置地址的大小,在32位环境下为4字节,在64位环境下位8字节,打印结果为4或者8


printf("%d\n",sizeof(&a[0]));

a[0]表示的是数组首元素1,&a[0]就是将首元素1的地址取出,因此sizeof(&a[0])求出的就是首元素的地址大小,在32位环境下为4字节,在64位环境下位8字节,打印结果为4或者8


printf("%d\n",sizeof(&a[0]+1));

a[0]表示的是数组首元素1,&a[0]就是将首元素1的地址取出,再对&a[0]+1得出的就是数组第二个元素的地址,在32位环境下为4字节,在64位环境下位8字节,打印结果为4或者8


 2.2 字符数组

代码1

char arr[] = {'a','b','c','d','e','f'};
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));

char arr[ ] = {'a','b','c','d','e','f'};


printf("%d\n", sizeof(arr));

在此数组名单独在sizeodf内表示的是整个数组,有因为每个数组元素为char类型,大小为1字节,所以结果就为6字节,输出结果为6


printf("%d\n", sizeof(arr+0));

在此数组名arr不是单独放在sizeof内,因此arr表示的就是数组首元素的地址,又因为sizeof(arr)=sizeof(arr+0),求出的为首元素地址大小,在32位环境下为4字节,在64位环境下位8字节,打印结果为4或者8


printf("%d\n", sizeof(*arr));

在此数组名arr不是单独放在sizeof内,因此arr表示的就是数组首元素的地址,再对arr解引用后表示的就是数组首元素,所以sizeof(*arr)计算的就是首元素大小,大小为1,输出结果为1


printf("%d\n", sizeof(arr[1]));

arr[1]表示的是数组第二个元素b,因为数组arr每个元素类型为都为char,大小为1字节,所以sizeof(arr[1])大小为1,输出结果为1


printf("%d\n", sizeof(&arr));

在此&arr取出的是整个数组arr的地址,sizeof(&arr)求出的就是整个数组地址大小,在32位环境下为4字节,在64位环境下位8字节,打印结果为4或者8


printf("%d\n", sizeof(&arr+1));

在此&arr取出的是整个数组arr的地址,再加一求出的是跳过整个数组那个位置的地址,

在32位环境下为4字节,在64位环境下位8字节,打印结果为4或者8


printf("%d\n", sizeof(&arr[0]+1));

arr[0]表示的是数组第一个元素,再&得出首元素的地址,再对该地址加一得到的就是数组第二个元素的地址,在32位环境下为4字节,在64位环境下位8字节,打印结果为4或者8


 代码2:

char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr+0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr+1));
printf("%d\n", strlen(&arr[0]+1));

char arr[ ] = {'a','b','c','d','e','f'};


printf("%d\n", strlen(arr));

在此数组名arr表示的是数组首元素的地址,由于字符数组arr种无\0,所以从首元素到\0之间的元素个数为随机值,输出结果为随机值


printf("%d\n", strlen(arr+0));

在此数组名arr表示的是数组首元素的地址,arr+0表示的还是首元素,由于字符数组arr种无\0,所以从首元素到\0之间的元素个数为随机值,输出结果为随机值


printf("%d\n", strlen(*arr));

在此*arr得出的是数组首元素a,在strlen中传参数不为指针时,程序会奔溃


printf("%d\n", strlen(arr[1]));

在此arr[1]表示的是数组第二个元素b,在strlen中传参数不为指针时,程序会奔溃


printf("%d\n", strlen(&arr));

在此&arr得出的是数组arr的地址,由于字符数组arr种无\0,所以从首元素到\0之间的元素个数为随机值,输出结果为随机值


printf("%d\n", strlen(&arr+1));

在此&arr得出的是数组arr的地址,再加一求出的是跳过整个数组那个位置的地址,由于字符数组arr种无\0,所以从这个元素到\0之间的元素个数为随机值,输出结果为随机值


printf("%d\n", strlen(&arr[0]+1));

在此&arr[0]得出的是数组首元素的地址,再加一得到的就是第二个元素的地址,由于字符数组arr种无\0,所以从第二个元素到\0之间的元素个数为随机值,输出结果为随机值


代码3: 

char arr[] = "abcdef";
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));

char arr[ ] = "abcdef";


printf("%d\n", sizeof(arr));

在此数组名arr表示的是数组首元素的地址,所以sizeof内求出的是整个数组的大小为6字节,输出结果为6


printf("%d\n", sizeof(arr+0));

在此数组名arr表示的是数组首元素的地址,arr+0表示的还是首元素地址,所以sizeof内求出的是整个数组的大小为6字节,输出结果为6


printf("%d\n", sizeof(*arr));

在此*arr得出的是数组首元素a,所以sizeof内求出的是数组首元素的大小为1字节,输出结果为1


printf("%d\n", sizeof(arr[1]));

在此arr[1]表示的是数组第二个元素b,所以sizeof内求出的是数组第二个元素的大小为1字节,输出结果为1


printf("%d\n", sizeof(&arr));

在此&arr得出的是整个数组arr的地址,在32位环境下为4字节,在64位环境下位8字节,打印结果为4或者8


printf("%d\n", sizeof(&arr+1));

在此&arr得出的是数组arr的地址,再加一求出的是跳过整个数组那个位置的地址,在32位环境下为4字节,在64位环境下位8字节,打印结果为4或者8


printf("%d\n", sizeof(&arr[0]+1));

在此&arr[0]得出的是数组首元素的地址,再加一得到的就是第二个元素的地址,所以sizeof内求出的是数组第二个元素的大小为1字节,输出结果为1


 代码4:

char arr[] = "abcdef";
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr+0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr+1));
printf("%d\n", strlen(&arr[0]+1));

char arr[ ] = "abcdef";


printf("%d\n", strlen(arr));

在此数组名arr表示的是数组首元素的地址,由于字符串arr末尾含有\0,所以从首元素到\0之间的元素个数为6,输出结果为6


printf("%d\n", strlen(arr+0));

在此数组名arr表示的是数组首元素的地址,arr+0表示的还是首元素,由于字符串arr末尾含有\0,所以从首元素到\0之间的元素个数为6,输出结果为6


printf("%d\n", strlen(*arr));

在此*arr得出的是数组首元素a,在strlen中传参数不为指针时,程序会奔溃


printf("%d\n", strlen(arr[1]));

在此arr[1]表示的是数组第二个元素b,在strlen中传参数不为指针时,程序会奔溃


printf("%d\n", strlen(&arr));

在此&arr得出的是数组arr的地址,由于字符串arr末尾含有\0,所以从首元素到\0之间的元素个数为6,输出结果为6


printf("%d\n", strlen(&arr+1));

在此&arr得出的是数组arr的地址,再加一求出的是跳过整个数组那个位置的地址,而字符数组内的\0已经在该指针前,所以到下一个\0之间的元素个数为随机值,输出结果为随机值


printf("%d\n", strlen(&arr[0]+1));

在此&arr[0]得出的是数组首元素的地址,再加一得到的就是第二个元素的地址,由于字符串arr末尾含有\0,所以从第二个元素到\0之间的元素个数为5,输出结果为5


代码5: 

char *p = "abcdef";
printf("%d\n", sizeof(p));
printf("%d\n", sizeof(p+1));
printf("%d\n", sizeof(*p));
printf("%d\n", sizeof(p[0]));
printf("%d\n", sizeof(&p));
printf("%d\n", sizeof(&p+1));
printf("%d\n", sizeof(&p[0]+1));

char *p = "abcdef";

在此字符指针中存放了一个常量字符串首元素的地址,指针p表示的是字符串首元素的地址


printf("%d\n", sizeof(p));

在此计算的是指针变量p的大小,在32位环境下为4字节,在64位环境下位8字节,打印结果为4或者8


printf("%d\n", sizeof(p+1));

p+1得到的是字符串中第二个元素b的地址,在32位环境下为4字节,在64位环境下位8字节,打印结果为4或者8


printf("%d\n", sizeof(*p));

在此p表示的是字符串首元素a的地址,*p是对指针p进行解引用,得到的就是字符串的首元素,在内存空间所占大小为1字节,输出结果为1

printf("%d\n", sizeof(p[0]));

p[0]=*(p+0),在此p[0]得到的就是字符串的首元素,在内存空间所占大小为1字节,输出结果为1


printf("%d\n", sizeof(&p));

在此&p得到的是指针变量p的地址,在32位环境下为4字节,在64位环境下位8字节,打印结果为4或者8 (注:在此&p是一个二级指针)


printf("%d\n", sizeof(&p+1)); 

在此&p得到的是指针变量p的地址,后再加一是跳过了p变量,指向了p后面的地址,在32位环境下为4字节,在64位环境下位8字节,打印结果为4或者8


printf("%d\n", sizeof(&p[0]+1));

在此p[0]=*(p+0,这时&就可以与*相抵消,得到sizeof(p+1),p+1得到的是字符串中第二个元素b的地址,在32位环境下为4字节,在64位环境下位8字节,打印结果为4或者8


代码6: 

char *p = "abcdef";
printf("%d\n", strlen(p));
printf("%d\n", strlen(p+1));
printf("%d\n", strlen(*p));
printf("%d\n", strlen(p[0]));
printf("%d\n", strlen(&p));
printf("%d\n", strlen(&p+1));
printf("%d\n", strlen(&p[0]+1));

char *p = "abcdef";

在此指针变量p存放的是常量字符串中a的地址,同时常量字符串末尾包含\0


printf("%d\n", strlen(p));

strlen求出的是首元素到\0之间的元素个数,也就字符串中的元素个数为6,输出结果为6


printf("%d\n", strlen(p+1));

p+1得到的是字符串中第二个元素b的地址,strlen求出的是第二个元素到\0之间的元素个数,也就字符串中的元素个数为5,输出结果为5


printf("%d\n", strlen(*p));

*p得到的是字符串的首元素a,程序会奔溃


printf("%d\n", strlen(p[0]));

在此p[0]=*(p+0),得到就是字符串的首元素a,程序会崩溃


printf("%d\n", strlen(&p));

在此&p得到的是指针变量p的地址,而在此地址中无\0需要向后找到\0才停止,所以结果为随机值,输出结果为随机值


printf("%d\n", strlen(&p+1));

在此&p得到的是指针变量p的地址,再加上一得到的是跳过过了变量p,指向了后边,而在此地址中无\0需要向后找到\0才停止,所以结果为随机值,输出结果为随机值


printf("%d\n", strlen(&p[0]+1)); 

在此p[0]=*(p+0),&可与*相抵消,最终只剩strlen(p+1),strlen求出的是第二个元素到\0之间的元素个数,也就字符串中的元素个数为5,输出结果为5


2.3 二维数组

int a[3][4] = {0};
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(a[0][0]));
printf("%d\n",sizeof(a[0]));
printf("%d\n",sizeof(a[0]+1));
printf("%d\n",sizeof(*(a[0]+1)));
printf("%d\n",sizeof(a+1));
printf("%d\n",sizeof(*(a+1)));
printf("%d\n",sizeof(&a[0]+1));
printf("%d\n",sizeof(*(&a[0]+1)));
printf("%d\n",sizeof(*a));
printf("%d\n",sizeof(a[3]));

 int a[3][4] = {0};

二维数组a可以看作是由3个一维数组组成的,每个一维数组有4个元素


printf("%d\n",sizeof(a));

数组名单独放在sizeof内得出的是整个数组的大小,a数组元素类型为int,所以整个数组大小为48字节,输出结果为48


printf("%d\n",sizeof(a[0][0]));

在此a[0][0]=*(*(a+0)+0),得到的是数组第一个元素,该元素大小为4,输出结果为4


printf("%d\n",sizeof(a[0]));

在此a[0]得到的是二维数组中的第一行的数组名,单独放在sizeof内,第一行有4个元素,大小为16字节,输出结果为16


printf("%d\n",sizeof(a[0]+1));

在此a[0]+1=*(a+0)+1,得到是第一行的第二个元素的地址,在32位环境下为4字节,在64位环境下位8字节,打印结果为4或者8


printf("%d\n",sizeof(*(a[0]+1)));

*(a[0]+1))=*(*(a+0)+1)得到的是二维数组内第一行的第二个元素,大小为4,输出结果为4


printf("%d\n",sizeof(a+1));

在此a表示二维数组首元素的地址也就是数组第一行的地址,再加上一得到的就是数组第二行的的地址在32位环境下为4字节,在64位环境下位8字节,打印结果为4或者8


printf("%d\n",sizeof(*(a+1)));

a+1得到的是二维数组第二行的地址,再解引用后得到是二维数组内第二个一维数组的数组名,单独放在sizeof内求出是整个一维数组的大小,一共有4个元素,大小为16字节,输出结果为16


printf("%d\n",sizeof(&a[0]+1));

在此&a[0]得到就是二维数组第一行的地址,再加一得到为第二行的地址,在32位环境下为4字节,在64位环境下位8字节,打印结果为4或者8


printf("%d\n",sizeof(*(&a[0]+1)));

在此&a[0]得到就是二维数组第一行的地址,再加一得到为第二行的地址,再进行解引用后得到是二维数组内第二个一维数组,sizeof求出的就是这个一维数组的大小,有4个元素,大小为16字节,输出结果为16

printf("%d\n",sizeof(*a));

在此a不是单独放在sizeof内,所以a表示的是二维数组首元素的地址即是第一个一维数组的地址,再进行解引用因为指针a类型为int(*)[4],所以sizeof求出的是数组第一行的大小,大小为16字节,输出结果为16


printf("%d\n",sizeof(a[3]));

a[3]=*(a+3),得到的是数组第四行的数组名,也有4个int类型的元素(虽然a[3]不存在,但我们知道sizeof内部表达式时不会真正计算的)大小为16字节,输出结果为16

3. 指针运算笔试题解析

3.1 题目1

#include <stdio.h>
//以上程序的结果是什么呢?
int main()
{
int a[5] = { 1, 2, 3, 4, 5 };
int *ptr = (int *)(&a + 1);
printf( "%d,%d", *(a + 1), *(ptr - 1));
return 0;
}

a表示数组首元素的地址,再加一解引用得到就是数组第二个元素2
&a+1原来的类型是int(*)[5]后强制类型转换为int*,这就改变了指针加减时的步长,所以str再减一步长就为4,得到的是数组第五个元素的地址,再解引用后就得到第五个元素5 

所以输出结果为2 5

3.2 题目2

//在X86环境下
//假设结构体的⼤⼩是20个字节
//以上程序输出的结果是什么呢?
struct Test
{
int Num;
char *pcName;
short sDate;
char cha[2];
short sBa[4];
}*p = (struct Test*)0x100000;
int main()
{
printf("%p\n", p + 0x1);
printf("%p\n", (unsigned long)p + 0x1);
printf("%p\n", (unsigned int*)p + 0x1);
return 0;
}

在以上代码中先创建了一个struct Test的结构体类型,后再创建一个结构体指针变量p,并将0x00100000这个整形的16进制数字强制类型转换为struct Test*后存储在p指针变量内
因此对指针变量p+0x1,因为指针变量类型为struct Test*,该结构体大小为20字节,所以指针加1后步长为20字节,又因为%p打印的是16进制的数,所以指针变量变为0x00100014


将指针变量强制类型转换为unsigned long后,因为对整型变量加一就是直接加一又因为%p打印的是16进制的数,所以变量就变为0x00100001


将指针变量强制类型转换为unsigned int*后,因为unsigned int的大小是4个字节,所以指针变量加一的步长是4个字节,又因为%p打印的是16进制的数,所以指针变量变0x00100004

最终输出结果为:
0x00100014
0x00100001
0x00100004

3.3 题目3

#include <stdio.h>
//以上程序输出的结果是什么呢?
int main()
{
int a[3][2] = { (0, 1), (2, 3), (4, 5) };
int *p;
p = a[0];
printf( "%d", p[0]);
return 0;
}

 由于二维数组内存在逗号表达式,括号内最终结果为逗号最后的值
 因此最终应为int a[3][2]={1,3,5}

 

所以p[0]就为数组中首元素1
输出结果为1

3.4 题目4

//假设环境是x86环境,程序输出的结果是啥?
#include <stdio.h>
int main()
{
int a[5][5];
int(*p)[4];
p = a;
printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
return 0;
}

 在以上代码中先将指针存放在指针变量p中,当a的类型是int(*)[5],而int(*)[4],两个变量类型不同,这时在变量p就会遵循int(*)[4]这个类型,&p[4][2]就是指针变量p跳过4个16字节后再跳过2个4字节得到处的地址,又因为&a[4][2]得到的是数组a第5行第2列的元素地址,这两地址处相减后就得到之间的元素个数为-4

%p就是将-4的补码按照16进制的方式打印出,因为4个二进制位数表示一个16进制数
所以补码转换为16进制就为:0xFFFFFFFC

输出结果为0xFFFFFFFC

3.5 题目5 

#include <stdio.h>
int main()
{
int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int *ptr1 = (int *)(&aa + 1);
int *ptr2 = (int *)(*(aa + 1));
printf( "%d,%d", *(ptr1 - 1), *(ptr2 - 1));
return 0;
}

 

首先先将&aa+1强制类型转换为int*后存储在指针变量ptr1中,再将 *(aa+1)也就是aa[1]强制类型转换为int*后存储在指针变量ptr2中,因此在对str1和str2减一时步长为4,再解引用后分别得到为10 5

所以输出结果为10 5

3.6 题目6 

#include <stdio.h>
int main()
{
char *a[] = {"work","at","alibaba"};
char**pa = a;
pa++;
printf("%s\n", *pa);
return 0;
}

a是一个字符指针数组,存放的是w,a,a三个字符的地址 ,而pa指针变量是一个二级指针,存放p指针变量的地址,同时指向的是存放p中首元素w的地址的地址
 

再对pa++后就使得pa变量指向的为p中第二个元素,也就是存放a的地址的地址,再*pa后就得到a的地址,再%s打印就可以将字符串at打印出

输出结果为at

3.7 题目7

#include <stdio.h>
int main()
{
char *c[] = {"ENTER","NEW","POINT","FIRST"};
char**cp[] = {c+3,c+2,c+1,c};
char***cpp = cp;
printf("%s\n", **++cpp);
printf("%s\n", *--*++cpp+3);
printf("%s\n", *cpp[-2]+3);
printf("%s\n", cpp[-1][-1]+1);
return 0;
}

以上图示就将各指针数组和指针变量之间的关系清晰的展现出

后先是**++cpp关系图就变为了以下形式

 先是++cpp就使cpp指针变量指向为cp[1],再*得到c+2,再*得到字符P的地址

之后 *--*++cpp+3关系图就变为了以下形式 

先++cpp后就使cpp指针变量指向为cp[2],再*得到cp[2],再--使cp[2]指向变为c[0],再*得到c[0]也就是字符E的地址,再对该地址+3就使指针指向了ENTER中的第四个字符
 

 在 *cpp[-2]+3=**(cpp-2)+3关系图就变为了以下形式 

先cpp-2后就使cpp指针变量指向为cp[0],再*得到cp[0],再*得到c[3]也就是字符F的地址,再对该地址+3就使指针指向了ENTER中的第四个字符

cpp[-1][-1]+1=*(*(cpp-1)-1)+1关系图就变为了以下形式

先cpp-1后就使cpp指针变量指向为cp[1],再*得到cp[1],再-1使cp[1]指向变为c[1],再*得到c[1]也就是字符N的地址,再对该地址+1就使指针指向了NEW中的第二个字符

所以以上代码输出结果为:
POINT
ER
ST
EW

以上就深入理解指针(5)的全部内容,希望看完以上内容你能有所收获,到此就是深入理解指针章节的全部内容了,感谢你的支持,接下来我将会继续带来c语言其他的知识,希望能得到你的点赞,收藏

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1696042.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【408精华知识】指令的寻址方式

文章目录 一、指令寻址&#xff08;一&#xff09;顺序寻址&#xff08;二&#xff09;跳跃寻址 二、数据寻址&#xff08;一&#xff09;隐含寻址&#xff08;二&#xff09;立即&#xff08;数&#xff09;寻址&#xff08;三&#xff09;直接寻址&#xff08;四&#xff09;…

网络域名是什么意思

网络域名&#xff0c;顾名思义&#xff0c;就是网络上的名字&#xff0c;类似于现实中的地址或姓名一样&#xff0c;用来标识网络上的一个或一组计算机或服务器的位置&#xff0c;以及它们的相应服务资源。网络域名是互联网上最基础的基础设施之一&#xff0c;是网络通信的“标…

虚机配置USB CDROM设备热迁移crash

虚机配置USB CDROM设备热迁移crash 问题现象定位过程堆栈分析日志分析打开trace异常日志上下文分析SpecificationCBWCSW 命令执行发送读命令读取数据 正常日志异常堆栈 修复方案结论 基础原理设备模型数据结构设备实例化 UHCIFrame ListTDQH SCSI 问题现象 dogfood环境一台虚机…

Echarts图表使用

ECharts是一个用JS实现开源可视化库&#xff0c;它提供了丰富的图表类型和交互能力。使用户可以通过简单的配置生成各种各样的图表。 先安装ECharts图表直接下载echarts.min.js并用<script>标签引入也可以使用源代码版本echarts.js并用<script>标签引入&#xff0…

【vue3+elementuiplus】el-select下拉框会自动触发校验规则

场景&#xff1a;编辑弹框省份字段下拉框必填&#xff0c;触发方式change&#xff0c;有值第一次打开不会触发校验提示&#xff0c;关闭弹框再次打开触发必填校验提示&#xff0c;但是该字段有值 问题的原因是&#xff1a;在关闭弹层事件中&#xff0c;我做了resetfileds&…

【kubernetes】陈述式资源管理的kubectl命令合集

目录 前言 一、K8s 资源管理操作方式 1、声明式资源管理方式 2、陈述式资源管理方式 二、陈述式资源管理方式 1、kubectl 命令基本语法 2、查看基本信息 2.1 查看版本信息 2.2 查看资源对象简写 2.3 配置kubectl命令自动补全 2.4 查看node节点日志 2.5 查看集群信息…

C++ | Leetcode C++题解之第112题路径总和

题目&#xff1a; 题解&#xff1a; class Solution { public:bool hasPathSum(TreeNode *root, int sum) {if (root nullptr) {return false;}if (root->left nullptr && root->right nullptr) {return sum root->val;}return hasPathSum(root->left…

立体库堆垛机的精密构造与功能(收藏版)

导语 大家好&#xff0c;我是社长&#xff0c;老K。专注分享智能制造和智能仓储物流等内容。 新书《智能物流系统构成与技术实践》 在现代物流仓储体系中&#xff0c;堆垛机以其高效、精准的操作能力&#xff0c;成为了自动化存储与检索系统的关键所在。 其复杂的构造和多样化的…

基于开源二兄弟MediaPipe+Rerun实现人体姿势跟踪可视化

概述 本文中&#xff0c;我们将探索一个利用开源框架MediaPipe的功能以二维和三维方式跟踪人体姿势的使用情形。使这一探索更有趣味的是由开源可视化工具Rerun提供的可视化展示&#xff0c;该工具能够提供人类动作姿势的整体视图。 您将一步步跟随作者使用MediaPipe在2D和3D环…

Windows远程连接命令?

Windows操作系统提供了多种远程连接命令&#xff0c;使用户可以通过网络连接到远程计算机&#xff0c;并在远程操作系统上执行操作。远程连接命令可方便实现远程工作、故障排查和系统维护等任务。本文将介绍几种常见的Windows远程连接命令及其基本使用方法。 远程连接命令 Win…

从0开始带你成为Kafka消息中间件高手---第一讲

从0开始带你成为Kafka消息中间件高手—第一讲 网站的用户行为日志&#xff0c;假设电商网站&#xff0c;我现在需要买一个阅读架&#xff0c;看书的架子 京东&#xff0c;我平时比较喜欢用的是京东&#xff0c;送货很快&#xff0c;自营商品&#xff0c;都是放在自己的仓库里…

Netty初识Hello World 事件循环对象(EventLoop) 事件循环组 (EventLoopGroup)

初始Netty-HelloWorld Netty在网络通信中的地位就如同Spring框架在JavaEE开发中的地位。 基于Netty网络通信开发简易的服务端、客户端&#xff0c;以实现客户端向服务端发送hello world&#xff0c;服务端仅接收不返回数据。 服务端代码&#xff1a; Slf4j public class Hell…

HCIP-Datacom-ARST自选题库__MPLS多选【25道题】

1.下列描述中关于MPLS网络中配置静态LSP正确的是 当某一台LSR为Egress LSR时&#xff0c;1仅需配置In Label&#xff0c;范围为16~1023 当某一台LSR为Transit LSR时&#xff0c;需要同时配置In Label和Out label&#xff0c;In Label范围为16~1023&#xff0c;0utLabel范围为…

【C语言】C语言-学生选修课程系统(源码)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

牛客NC302 环形数组的连续子数组最大和【中等 动态规划 Java/Go/PHP/C++】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/e9f3282363844355aa51497c5410beee 思路 动态规划 两种情况&#xff08;首位相连的&#xff09;和首位不相连的 首尾相连的可以算最小的连续子数组得出&#xff0c;sum-就是。Java代码 import java.util.*;pub…

Echarts - 多个页面内有N个 echarts 图表,封装组件 CommonEcharts 快捷实现

目录 子组件父组件使用注意 option 文件效果展示相关数据处理&#xff08;代码备份 - 可不看&#xff09;数据处理后页面展示 子组件 CommonEcharts.vue <template><div><div v-for"id in domId" :id"id" :key"id" class"…

springboot+vue+mybatis校园兼职平台+PPT+论文+讲解+售后

社会的发展和科学技术的进步&#xff0c;互联网技术越来越受欢迎。网络计算机的生活方式逐渐受到广大人民群众的喜爱&#xff0c;也逐渐进入了每个学生的使用。互联网具有便利性&#xff0c;速度快&#xff0c;效率高&#xff0c;成本低等优点。 因此&#xff0c;构建符合自己要…

十、通配符和正则表达式

10.1 通配符 通配符是由shell处理的, 它只会出现在 命令的“参数”里。当shell在“参数”中遇到了通配符 时&#xff0c;shell会将其当作路径或文件名去在磁盘上搜寻可能的匹配&#xff1a;若符合要求的匹配存在&#xff0c;则进 行代换(路径扩展)&#xff1b;否则就将该通配…

基于springboot+vue的致远汽车租赁系统

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

新兴勒索软件组织不断涌现:他们是谁,如何运作

新兴的勒索软件团伙正采取不同的策略和目标&#xff0c;填补大公司关闭和执法中断所留下的空白。 3 月份 BlackCat (ALPHV) 的关闭和 2 月份执法部门对 LockBit 基础设施的干扰导致勒索软件生态系统出现空白&#xff0c;而这一空白正迅速被经验不足的团体所填补。 今年到目前…