C语言----深入理解指针(5)
1.sizeof和strlen的对比
sizeof计算变量所占内存空间的大小的,单位是字节
sizeof只关注内存空间的大小,不在乎内存中方的什么数据
sizeof是操作符不是函数
sizeof会将\0算进去的
// sizeof计算变量所占内存空间的大小的,单位是字节int main()
{int a = 10;printf("%d\n", sizeof(int));//输出结果是4printf("%d\n", sizeof(a));//输出结果是4int arr[10] = { 0 };printf("%d\n", sizeof(arr));//输出的结果是40return 0;
}//sizeof只管新占了多大的内存空间大小
那么strlen呢?
strlen是c语言里面的库函数,是函数
作用的求字符串长度的,只能针对字符串
strlen统计的是字符串\0之前的字符个数
只能指针字符串,求字符串长度
不能求整形数组的
strlen直到遇到\0,不然是不会停下来的
int main()
{char arr1[] = { 'a','b','c' };char arr2[] = "abc";//字符串末尾隐藏着一个\0printf("%zd\n", strlen(arr1));//15---往后找\0,直到找到\0才停止--那么这个15就是随机值printf("%zd\n", strlen(arr2));//3---\0前面有三个字符printf("%zd\n", sizeof(arr1));//3---只关乎arr1占了多大的空间printf("%zd\n", sizeof(arr2));//4---放了4个字符,包括\0,总共占了4个字节 //strlen是用来求字符串长度的,不能用来求整型数组return 0;
}
2.数组和指针笔试题解析
sizeof---一维数组
//恢复:数组名是数组首元素的地址
//但是有两个例外
//sizeof(数组名)
//&数组名
//除了这两种,其他的都是数组首元素的地址
int main()
{int a[] = { 1,2,3,4 };printf("%zd\n", sizeof(a));//16---4个元素,每个元素4个字节//数组名a单独放在sizeof内部,a表示的是整个数组,计算的是整个数组的大小,单位是字节printf("%zd\n", sizeof(a+0));//4//a是数组名,数组首元素的地址,a+0还是首元素的地址//a+i就是数组内下标为i的数组元素//这里的sizeof计算的是首元素地址的大小printf("%zd\n", sizeof(*a));//4//这里的a依然是首元素的地址,*a就是首元素,就是a[0]//因为arr[0]是一个整数,就是4个字节printf("%zd\n", sizeof(a+1));//4//因为数组名表示的是首元素的地址,那么首元素加1//就是下标为1的数字的地址,就是这个数组内第二个元素的地址//arr[1]的地址//这里计算的是地址的大小printf("%zd\n", sizeof(a[1]));//4//a[1]就是数组内第二个元素,就是4个字节的大小printf("%zd\n", sizeof(&a));//4//取出整个数组的地址//数组的地址也是一个地址啊,是地址就是4个字节的长度printf("%zd\n", sizeof(*&a));//16//取出a的地址,再进行解引用,就是整个数组,//*和&抵消了,就是整个数组// sizeof(*&a)==sizeof(a)//&a是数组的地址,类型是int(*)[4]---数组指针类型//那么*&a就是访问真个数组printf("%zd\n", sizeof(&a+1));//4//&a就是整个数组的地址,地址+1就是跳过整个数组后的那个地址,// 但是仍然是地址啊//是地址就是4个字节printf("%zd\n", sizeof(&a[0]));//4//arr[0]是数组首元素的地址,再将其取出//取出数组首元素的地址printf("%zd\n", sizeof(&a[0]+1));//4//将首元素的地址取出,再+1就是第二个元素的地址return 0;
}
sizeof--字符数组
int main()
{char arr[] = { 'a','b','c','d','e','f' };//没有\0printf("%d\n", sizeof(arr));//6//整个数组的大小,6个字符就是6printf("%d\n", sizeof(arr+0));//4//arr是首元素的地址,arr+0还是首元素的地址,地址的字节就是4printf("%d\n", sizeof(*arr));//1//对数组首元素地址进行解引用就是数组首元素,字符就是1个字节printf("%d\n", sizeof(arr[1]));//1//数组中下标为1的字符,大小是1个字节printf("%d\n", sizeof(&arr));//4//取出整个数组的地址,仍然是地址,地址就是4个字节的大小printf("%d\n", sizeof(&arr+1));//4//取出整个数组的地址,+1跳过整个数组,还是地址,就是4个字节的大小printf("%d\n", sizeof(&arr[0]+1));//4//取出数组首元素的地址,再+1就是第二个元素的地址,地址是4个字节大小return 0;
}
strlen---大括号--一堆字符
int main()
{char arr[] = { 'a','b','c','d','e','f' };//没有\0printf("%zd\n", strlen(arr));//随机值//这里的arr表示的是首元素的地址//从首元素开始数字符,一直数到\0之前才停止//那么这里的值就是随机值printf("%zd\n", strlen(arr+0));//arr+0还是数组名-----首元素的地址//那么返回的值就是随机值,这个代码和上面的代码没有区别//并且这两个随机值是一样的printf("%zd\n", strlen(*arr));//arr是首元素的地址,那么对其进行解引用就是数组第一个元素,就是'a'字符//strlen(a)---'a'的ASCII的大小是97,strlen不能运行//a的值传递给strlen,strlen会认为97是地址,然后会访问内存//这个代码是有问题的printf("%zd\n", strlen(arr[1]));//arr[1]是数组下标为1的元素//strlen('b')---'b'的ASCII大小是98//这个程序也会崩溃printf("%zd\n", strlen(&arr));//随机值//将数组的整个数组的地址传过去了//strlen依然从首元素往后数//依然没有遇到\0//那么返回值就是随机值//&arr的类型是----char(*)[6]printf("%zd\n", strlen(&arr+1));//随机值//取出整个数字的地址,然后+1跳过整个数组//也是随机值,不知道什么时候遇到\0printf("%zd\n", strlen(&arr[0]+1));//随机值//arr[0]是数组首元素,+1就是b,那么strlen往后直到遇到\0才停止,那么//这个代码返回的也是随机值return 0;
}
sizeof--字符串
//数组名是数组首元素的地址
//两个例外:
//sizeof(arr)
//&arr---这里的数组名表示整个数组,取出的是数组的地址int main()
{char arr[] = "abcdef";//字符串初始化//这个字符串末尾还有一个\0printf("%zd\n", sizeof(arr));//7//arr作为数组名,这里计算的是这个数组的大小//一个字符一个字节,那么这里就是7个字节//这里的数组名是单独的放在sizeof里面的printf("%zd\n", sizeof(arr + 0));//4//数组名--就是数组首元素的地址//这里的arr并不是单独的放在sizeof里面//那么这里的arr+0是首元素的地址//既然是地址,那么大小就是4个字节printf("%zd\n", sizeof(*arr));//1//这里的arr是数组名--首元素的地址//对arr进行解引用达到的就是首元素//首元素的大小是1个字节--每个字符的大小是1个字节printf("%zd\n", sizeof(arr[1]));//1//数组下标为1的元素,字符,所以大小也是1printf("%zd\n", sizeof(&arr));//4//取出整个数组的地址,地址就是4个字节printf("%zd\n", sizeof(&arr + 1));//4//取出的是整个数组的地址,再+1,得到的就是跳过整个数组//得到的也是地址,既然是地址就是4个字节的大小printf("%zd\n", sizeof(&arr[0] + 1));//4//arr[0]是数组首元素,取出数组首元素的地址再+1//得到的就是数组内的第二元素的地址,地址就是4个字节大小//首元素的地址类型是char*return 0;
}
strlen---字符串
int main()
{char arr[] = "abcdef";//字符串末尾放着\0的printf("%d\n", strlen(arr));//6//这里的arr是首元素的地址// 从首元素开始数,数到\0之前就停止//strlen是求字符串长度的//因为末尾放着一个\0,那么strlen数的就是\0前面的字符个数//strlen是从第一个元素开始统计\0之前的字符个数printf("%d\n", strlen(arr + 0));//6//arr是首元素的地址,那么arr+0还是首元素的地址//那么把数组首元素的地址传给strlen,就是从首元素开始统计,直到遇到\0printf("%d\n", strlen(*arr));//arr是首元素的地址,那么解引用得到的就是首元素字符'a'//'a'的大小是97,将97当成地址传递给strlen,97这个地址不能被访问,这个程序就崩溃了printf("%d\n", strlen(arr[1]));//arr[1]是数组下标为1的元素,第二个元素,访问的是'b'//这个代码的道理和上面的一样,一样会崩溃的printf("%d\n", strlen(&arr));//6//取出数组的地址,将取出的地址存放至数组指针变量里面这么写//char(*pa)[7]=&arr
//那么pa的类型是char(*)[7]//但是对于strlen这个库函数来说//size_t strlen (const char* str)//硬要将char(*)[7]这个地址传过去,因为char(*)[7]与const char* str不一致,会导致将传过来的指向强制转换为strlen所需要的类型////数组的地址和数组首元素的地址是指向同一个位置的//那么strlen也是从第一个元素的位置开始向后访问//所以这个代码实现的数据是6printf("%d\n", strlen(&arr + 1));//随机值//取出数组的地址,再+1就是跳过整个数组,那么strlen遇到\0才会停止//那么这里的就是随机值printf("%d\n", strlen(&arr[0] + 1));//5//取出的是首元素的地址,那么首元素的地址+1就是数组第二个元素的地址//那么strlen就从第二个元素开始访问进行统计的//那么这里的 数据就是5return 0;
}
//在这些代码运行的时候
//会出现很多警告
//因为我们在传参的时候类型不一致
//&arr的类型是char(*)[7],而strlen只能接受const char* str这个类型的指针
sizeof---指针
int main()
{char* p = "abcdef";//将首字符的地址存放在p中printf("%zd\n", sizeof(p));//4//p是指针变量。那么sizeof(p)计算的就是指针变量p的大小//因为一个指针变量的大小是4个字节--x86的情况下,x64的情况下是8个字节printf("%zd\n", sizeof(p + 1));//4//p存的是首元素的地址,p的类型是char*//那么p+1得到的是b的地址,就是相当于跳过了一个字符//地址的大小就是4个字节printf("%zd\n", sizeof(*p));//1//p是字符串首元素的地址,对p进行解引用,得到的就是首元素,首元素是字符a//a的字节大小是1//因为p的类型是char*,只能访问一个字节,就是aprintf("%zd\n", sizeof(p[0]));//1//p[0]-->*(p+0)---得到的就是字符a---大小为1个字节printf("%zd\n", sizeof(&p));//4//取出p的地址,&p是p的地址,对p的地址进行大小计算,地址的大小就是4个字节printf("%zd\n", sizeof(&p + 1));//4//取出p的地址进行+1操作// // // char* *ptr=&p ptr指向的p是一个类型为char*类型的指针,后面的*说明ptr是一个指针//&p的指针类型是char * *,对&p+1就是跳过一个char* * 类型的对象//举例:int *p 对p+1跳过的就是一个整型对象//&p是p的地址,&p+1是跳过了p变量,指向了p的后面//因为&p+1是地址,就是4个字节printf("%zd\n", sizeof(&p[0] + 1));//4//p[0]是*(p+0)---就是首元素a//前面加上&得到的就是a的地址,+1就是b的地址//&p[0]就是preturn 0;
}
strlen---指针
int main()
{char* p = "abcdef";//将这个字符串首元素的地址存储在p中,末尾有\0printf("%zd\n", strlen(p));//6//p里面放的是a的地址,//strlen(p)就是从a的地址开始统计这个字符串的长度//得到的数据是6printf("%zd\n", strlen(p + 1));//5//p存的是a的地址,因为p是char*的指针,那么p+1就是指向b的地址//就是从b的地址位置开始统计这个字符串的个数//那么得到的数据就是5printf("%zd\n", strlen(*p));//程序崩溃//*p是a,a是97//将97作为地址传给strlen,程序会崩溃的printf("%zd\n", strlen(p[0]));//程序崩溃//p[0]--->*(p+0)----*p---a----97//那么这个程序就会崩溃的printf("%zd\n", strlen(&p));//随机值//取出指针变量p的地址,那么strlen就从指针变量p地址开始统计,在p这块空间进行统计//那么得到的就是随机值printf("%zd\n", strlen(&p + 1));//随机值//&p是指针p的地址,+1就是跳过p的地址,开始进行统计//所以数据就是随机值printf("%zd\n", strlen(&p[0] + 1));//5//p[0]--->*(p+0)----*p---a//那么&p[0]就相当于p,//p里面存的是a的地址,+1得到的是b的地址//那么我们就从b的位置开始统计//得到的数据是5return 0;
}
//注意:p[0]--->*(p+0)----*p---a
sizeof---二维数组
//二维数组
int main()
{int a[3][4] = { 0 };//3行4列----每一行都输一维数组//第一行的数组名叫arr[0]---每个元素的访问a[0][i]//第一行的数组名叫arr[1]---每个元素的访问a[1][i]//第一行的数组名叫arr[2]---每个元素的访问a[2][i]printf("%d\n", sizeof(a));//48//a是二维数组的数组名,单独放在sizeof内部,a表示的是整个数组,计算的就是整个数组的大小,单位是字节//12个元素,每个元素4个字节,总共就是48个字节大小printf("%d\n", sizeof(a[0][0]));//4//a[0][0]就是第一行第一个元素,大小是4个字节printf("%d\n", sizeof(a[0]));//16//a[0]是这个二维数组的第一行的数组名//第一行的数组名单独放在sizeof内部,计算的就是整个一维数组的大小,就是4*4=16个字节的大小printf("%d\n", sizeof(a[0] + 1));//4//a[0]是第一行的数组名,但是没有单独放在sizeof里面,就说明这里的a[0]是第一行首元素的地址,那么首元素地址+1就是第一行第二个元素的地址//就是a[0][0]的地址//那么a[0] + 1--->&arr[0][0]+1--->&a[0][1]//因为这里是地址,那么就是4个字节大小printf("%d\n", sizeof(*(a[0] + 1)));4//上面说a[0]+1得到的是第一行第二个元素的地址//那么我们解引用得到的就是第一行第二个元素,是一个整型,大小是4个字节printf("%d\n", sizeof(a + 1));//4//a + 1//a是二维数组的数组名,并且没有单独放在sizeof内//说明这个a是这个二维数组的首元素地址//就是第一行的地址,那么a+1就是第二行的地址//因为a+1是第二行的地址,传给sizeof,因为是地址,所以大小是4个字节//printf("%d\n", sizeof(*(a + 1)));//16//*(a+1)--->a[1]--第二行的数组名,单独放在sizeof内部,那么sizeof计算的就是第二行的大小//因为a+1得到的是第二行的地址,那么对其进行解引用,得到的就是第二行整个数组//a+1是第二行的地址,类型是int(*)[4],数组指针,基因用访问的是这个数组,大小是16个字节printf("%d\n", sizeof(&a[0] + 1));//4//a[0]是第一行的数组名,&数组名就是第一行的地址,&a[0]就是取出了第一行的地址//那么&a[0] + 1得到的就是第二行的地址//因为是地址,那么大小就是4个字节printf("%d\n", sizeof(*(&a[0] + 1)));//16//上面说到&a[0] + 1得到的是第二行的地址,那么对第二行的地址进行解引用得到的就是第二行数组//printf("%d\n", sizeof(*a));//16//a作为数组名没有单独放在sizeof内,那么a就不是整个数组//a就是这个二维数组的首元素的地址//对其进行解引用得到的就是第一行整个数组//4*4=16//*a-->*(a+0)-->a[0]printf("%d\n", sizeof(a[3]));//16//这里是否越界//sizeof内部的表达式是不会真实计算的,也不会真实去访问的// 仅仅只是根据类型来推断长度的//a[3]是第四行的数组名---那么计算的是第四行的大小//第四行的类型是int[4]return 0;
}//数组名在sizeof内单独使用,表示的就是整个数组
//如果不是单独使用,我们就要考虑一下这个数组名是数组首元素的地址//sizeof内部的表达式是不会进行运算的int main()
{short s = 8;//short类型的数据是2个字节int n = 12;//4个字节printf("%zd\n", sizeof(s = n + 5));//2//sizeof内部的表达式并没有进行运算//sizeof(s = n + 5)这个表达式 最终结果取决于sprintf("%zd\n", s);//8return 0;
}
数组名的意义:
1.sizeof(数组名),这里的数组名表示的是整个数组,计算的是整个数组的大小
2.&数组名,这里的数组名表示整个数组,取出的是整个数组的地址
3.除此之外所有的数组名都表示数组首元素的地址
3.指针运算笔试题解析
题目一
#include <stdio.h>
int main()
{int a[5] = { 1, 2, 3, 4, 5 };int* ptr = (int*)(&a + 1);//&a是取出真个数组的地址,那么&a+1就是跳过了整个数组,指向的是这个数组的末尾的位置//&a+1的地址类型是数组类型的地址int(*)[5]//将这个地址强制类型转换为int*类型的//准换位int*类型的地址再赋值给ptr,那么ptr指向的也是这个数组的末尾位置printf("%d,%d", *(a + 1), *(ptr - 1));//这里的a是数组名--数组首元素的地址,那么a+1得到的就是第二个元素的地址,就是2的地址//解引用得到的就是2//因为ptr现在是整型指针,那么-1就是往回退,那么指向的就是5的位置//*(ptr - 1)得到的就是5return 0;
}
//&a+1就是取出整个数组再跳过这个数组,就是那么这个&a+1指向的就是这个数组的末尾
//再将这个强制类型转换为int *类型的地址,再赋值给ptr
//那么ptr也是指向这个数组的末尾的位置
//因为ptr的类型是int *,-1就是往后退一个整型的距离,那么就是指向的5的位置
题目二
//在X86环境下
//假设结构体的⼤⼩是20个字节
//程序输出的结果是啥?
struct Test
{ int Num;char* pcName;short sDate;char cha[2];short sBa[4];
}*p = (struct Test*)0x100000;
//在这里括号前面的是结构体,加上*就是结构体指针类型,创建变量p
//先将0x100000强制转换为结构体指针,再为b进行赋值,现在p里面放的就是0x100000这个地址int main()
{printf("%p\n", p + 0x1);//00100014//指针+1和类型有关系//整数+1就是+1//0x1是16进制的1//因为p是一个结构体指针,因为前面说了结构体的大小是20字节// 那么p+1就是就是跳过跳过一个结构体20个字节//0x100014
//因为这个是16进制的,所以加20个字节就是在这个基础上+14
//4*16的0次方+1*16的1次方就是20//00100014printf("%p\n", (unsigned long)p + 0x1);//0x00100001//现在将p强制类型转换为整型,那么整型+1就是+1//那么得到的就是0x00100001printf("%p\n", (unsigned int*)p + 0x1);//00100004//将p强制类型转换为int *//+1跳过一个unsigned int*类型的指针变量,是4个字节return 0;
}
题目三
#include <stdio.h>
int main()
{int a[3][2] = { (0, 1), (2, 3), (4, 5) };//仔细看,这里用的是小括号不是大括号//那么这里就成逗号表达式了//(0, 1)的结果就是1//(2, 3)的结果就是3//(4, 5)的结果就是5//int a[3][2] = { 1,3,5 };//那么这个二维数组剩下的位置就被0给填充了//1 3//5 0//0 0int* p;//指针p = a[0];//a[0]是第一行的数组名,// 没有sizeof// 没有&// // 那么表示的就是首元素的地址//那么p里面存的就是1的地址printf("%d", p[0]);//p[0]===*p(0)--指向的还是1的位置//那么打印出来的就是1return 0;
}
题目四
//假设环境是x86环境,程序输出的结果是啥?
#include <stdio.h>
int main()
{int a[5][5];//5行5列//每一行的数组名分别是a[0]、a[1]、a[2]、a[3]、a[4]int(*p)[4];//p是一个数组指针,p指向的数组有4个元素,每个元素是intp = a;//a是数组名,这个二维数组的数组名,就是第一行的地址,第一行整个一维数组的地址//第一行的地址的类型就是一个数组指针int(*)[5]//p的类型是int(*)[4] a的类型是int(*)[5]//不管a原来是什么类型,现在赋值给p,那么现在就是p说的算//因为a指向的是第一行的位置,那么p同样也指向那里//对于p来说,一行只有4个元素//p+1就是跳过一行,每行四个元素printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);//FFFFFFFC,-4//p[4][2]==*(*(p+4)+2)-----解引用p+4就相当于拿到那一行的数组名//两个地址相减是地址直接的元素个数,这中间差了4个元素//小地址减去大地址得到的是-4//第一个代码是打印地址的,因为相减的结果是-4,存在内存里面,那么直接把存放-4的地址打印出来了//-4在内存里面存的是补码//11111111111111111111111111111100//打印地址直接将内存里面的这个二进制补码直接当成地址//4个二进制的1就是一个F,最后剩下的1100就是12,转换成6进制就是Creturn 0;
}
//考察的是指针的运算,数组指针+1跳过的是多少
//就是跳过一个指针类型,在这里p+1就是跳过一行
题目五
#include <stdio.h>
int main()
{int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };//两行5列int* ptr1 = (int*)(&aa + 1);//&aa就是取出整个二维数组的地址,+1就是跳过整个二维数组//&aa+1得到的还是二维数组的地址,将这个地址强制类型转换为int *//因为&aa+1跳过的是整个数组,那么指向的位置就是这个二维数组的末尾//因为被强制转换为int *后再赋值给ptr1,那么赋值后ptr1指向的位置也是这个二维数组的末尾//int* ptr2 = (int*)(*(aa + 1));//aa+1--->aa[1]---第二行的数组名---第二行首元素的地址//aa是数组名,表示的是首元素的地址,就是第一行的地址//那么aa+1就是第一行的地址+1指向的就是第二行的地址//那么对其进行解引用得到的就是第二行整个一维数组//因为这个第二行的一维数组本身就是整型,那么前面的int *可以忽略//现在将(int*)(*(aa + 1))赋值给ptr2,那么ptr2也是指向的第二行的数组//aa + 1可以理解为aa[1],就是第二行的数组名,就是第二行数组首元素的地址,就是指向的6printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));//10,5//在这里,因为ptr1指向的是数组的末尾,并且ptr1是整型指针,那么ptr1-1指向的就是10的位置//那么对其进行解引用得到的就是10//因为ptr2指向的是6,那么ptr2-1得到的就是5的地址,对其进行解引用得到的就是5return 0;
}
题目六
#include <stdio.h>
int main()
{char* a[] = { "work","at","alibaba" };//正常是不能这么放的,那么就是把每个字符串的首元素地址存在这个指针数组里面了//这里定义的指针数组里面存的分别是w、a、a的地址char** pa = a;//a是数组名,表示的是首元素的地址,就是第一个元素的地址//首元素的地址是char*类型的,那么存在pa里面,那么pa就是一个二级指针//那么char**pa指向的就是首元素pa++;//pa指向的是第一个元素,那么++就是指向的第二个元素,就是跳过提个char*类型的指针//那么下面的*pa得到的就是第二个元素的地址printf("%s\n", *pa);//at//得到了地址,那么就从地址开始打印对饮的字符串return 0;
}
题目七--最难的
#include <stdio.h>
int main()
{char* c[] = { "ENTER","NEW","POINT","FIRST" };//每个元素是char*//存放的是每个字符串首字符的地址,//分别是E、N、P、Fchar** cp[] = { c + 3,c + 2,c + 1,c };//c是上面的指针数组的数组名,指向的就是首元素的地址,指向的就是第一个字符串//c指向的就是"ENTER"//c+1指向的就是"NEW"//c+2指向的就是"POINT"//c+3指向的就是"FIRST"//将c里面首元素的地址存放在cp里面,那么cp的类型就是一个二级指针char*** cpp = cp;//cp是数组名,表示的是首元素的地址,将二级指针的地址放在三级指针内//cpp指向的是首元素的地址,就是c+3//下面的++和--会有副作用的,会改变指//int a=5 ++a 这个动作完了之后a的值就变为6了printf("%s\n", **++cpp);//POINT//* * ++ cpp//先算++cpp,cpp本来放的是c+3的地址,那么现在进行++之后,就指向了c+2的地址// 然后解引用,因为cpp现在指向的是c+2的地址,那么第一次解引用就得到了c+2// 第二次解引用就是对c+2解引用,得到的就是"POINT"//////printf("%s\n", *-- * ++cpp + 3);//ER//因为加法的优先级比较低,所以先算前面的// 所以先算++,再解引用,再--,再解引用// // 因为上面的cpp已经进行++操作了,指向的是c+2,那么再次++就是指向的c+1了// 那么现在已经得到了c+1的地址了// 现在进行解引用通过地址找到c+1,// // 原本放的是c+1,现在--就变成c了,就没有c+2了,--就是自减,c+1变成c了// c是指向的是"ENTER"这个字符串首元素E的地址,那么解引用完+3指向的就是E// //那么就是从E开始打印,所以只能打印ER// // // // ////printf("%s\n", *cpp[-2] + 3);//ST//*cpp[-2]是**(cpp+(-2))就是**(cpp-2)//// 一开始cpp指向的是原先的c+1的地址,但是c+1自减了1,就成c了,那么现在cpp指向的就是c的地址了// 那么cpp-2得到的就是c+3的地址// 这里的cpp-2不会导致cpp的改变,还是指向c// // 那么cpp-2得到的是c+2的地址,解引用得到的就是c+3// c+3指向的是这串字符串首元素字符F的地址---"FIRST"// // 最后F的地址+3就是S// 那么打印出来的就是ST// // 这里最关键的就是*cpp[-2]这个的理解//printf("%s\n", cpp[-1][-1] + 1);// EW//cpp[-1][-1] + 1//转换形式// *(*(cpp-1)-1)+1// 这里的cpp指向的是c的位置// 那么cpp-1就指向了c+2的位置// // *(cpp-1)拿到了c+2// 那么就变成下面这样了// *((c+2)-1)+1// c+2-1得到了c+1,就是现在的cpp指向的位置// // c+1指向的就是"NEW"//对c+1进行解引用就拿到了"NEW"--N的地址//然后N的地址+1得到的就是E的地址//然后打印出来的就是EWreturn 0;
}
相关文章:
C语言----深入理解指针(5)
1.sizeof和strlen的对比 sizeof计算变量所占内存空间的大小的,单位是字节 sizeof只关注内存空间的大小,不在乎内存中方的什么数据 sizeof是操作符不是函数 sizeof会将\0算进去的 // sizeof计算变量所占内存空间的大小的,单位是字节int m…...
Ansible——cron模块
目录 参数总结 示例1:创建一个定时任务 示例2:删除一个定时任务 示例3:每周一早上 3 点清理临时文件 示例4:每小时运行一次日志轮转 示例5:为指定用户添加一个定时任务 Playbook (YAML 格式) 中管理定时任务。 …...
保存图片奇怪的bug
今天发现一个奇怪的bug 这个的dpi是100de ,但是我取完切片之后,发现这个结果就变了...
【Go语言精进之路】构建高效Go程序:了解map实现原理并高效使用
🔥 个人主页:空白诗 🔥 热门专栏:【Go语言精进之路】 文章目录 引言一、什么是map1.1 map的基本概念与特性1.2 map的初始化与零值问题1.3 map作为引用类型的行为 二、map的基本操作2.1 插入数据2.2 获取数据个数2.3 查找和数据读取…...
【机器人和人工智能——自主巡航赛项】进阶篇
文章目录 案例要求创建地图rviz仿真 保存地图坐标点定位识别训练主逻辑理解语音播报模块匹配二维码识别多点导航讲解视频其余篇章 案例要求 创建地图 ./1-gmapping.sh 把多个launch文件融合在sh文件里面 rviz仿真 rviz是rose集成的可视化界面,查看机器人的各项数…...
[大师C语言(第二十五篇)]C语言字符串探秘
引言 字符串是编程中不可或缺的基本数据类型之一,它用于表示和操作文本数据。在C语言中,字符串以一种独特的方式实现,与许多其他编程语言的处理方式不同。本文将深入探讨C语言字符串背后的技术,帮助你更好地理解和应用字符串。 …...
xLua(一) 环境安装笔记
为了方便查阅记录一下xLua的安装地址及方法 1.登录地址下载: https://github.com/Tencent/xLua 2.解压文件 将文件中的这些内容拷贝到项目中的Asset文件夹中 注意 : 工程项目路径不得含有中文 3.将Tools复制到Asset同级目录下 4.导入后会发现有Bug,需要导入工程 5.还有另…...
Python基础教程(十一):数据结构汇总梳理
💝💝💝首先,欢迎各位来到我的博客,很高兴能够在这里和您见面!希望您在这里不仅可以有所收获,同时也能感受到一份轻松欢乐的氛围,祝你生活愉快! 💝Ὁ…...
制造型企业图纸泄露问题,如何从根源解决核心文件资料泄露问题?
制造型企业最核心重要的文件当然是图纸,图纸在制造型企业中起到关键主导地位,如果图纸泄露与研发性企业源代码被泄露一样的严重,制造型企业如何保护核心图纸不被外泄是企业在日常经营过程中的重要组成部分,现在有很多防止泄露的产…...
英伟达最新GPU和互联路线图分析
Nvidia在计算、网络和图形领域独树一帜,其显著优势在于雄厚的资金实力及在生成式人工智能市场的领先地位。凭借卓越的架构、工程和供应链,Nvidia能够自由实施创新路线图,引领行业未来。 到 21 世纪,Nvidia 已经是一个非常成功的创…...
Github 2024-06-10 开源项目日报 Top10
根据Github Trendings的统计,今日(2024-06-10统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量C项目2Go项目2PHP项目1Blade项目1TypeScript项目1Lua项目1Dart项目1Swift项目1Cuda项目1Python项目1MDX项目1Ventoy: 100%开源的可启动USB解决方…...
前后端分离项目中Spring Boot返回的时间与前端相差8个小时
概述 今天在做一个前后端分离项目时,发现从后端获取的时间与从数据库获取的时间相差八个小时,最终排查后发现由于Springboot使用本地时区导致,修改SpringBoot时区后解决 环境 MySQL8SpringBoot 原因排查 发现从后端获取的数据总是比前端快八个小时 …...
stm32MP135裸机编程:使用USB/UART烧录程序到SD卡并从SD卡启动点亮一颗LED灯
0 参考资料 轻松使用STM32MP13x - 如MCU般在cortex A核上裸跑应用程序.pdf STM32CubeProgrammer v2.16.0 烧录需要的二进制文件1 烧录到SD卡需要哪些文件 参考《轻松使用STM32MP13x - 如MCU般在cortex A核上裸跑应用程序》,烧录需要的SD卡文件如下: &a…...
【NoSQL数据库】Redis Cluster集群(含redis集群扩容脚本)
Redis Cluster集群 Redis ClusterRedis 分布式扩展之 Redis Cluster 方案功能数据如何进行存储 redis 集群架构集群伸缩向集群中添加一个新的master节点,并向其中存储 num10 .脚本对redis集群扩容缩容,脚本参数为redis集群,固定从6001移动200…...
重邮计算机网络803-(2)物理层
一.物理层 1.介绍 物理层的主要任务描述为确定与传输媒体的接口的一些特性,即: ①机械特性 指明接口所用接线器的形状和尺寸、引线数目和排列、固定和锁定装置等等。 ②电气特性 指明在接口电缆的各条线上出现的电压的范围。 ③功能特性 指明某条线上…...
uniapp使用webview内嵌H5的注意事项
一、描述 uniapp项目中构建app,需要内嵌H5页面,在使用webview时,遇到了以下几个问题: 内嵌H5,默认全屏显示;内嵌页面遮挡住了app的自定义tabbar组件;样式修改无效; 二、解决方案&a…...
现代 C++的高效并发编程模式
现代C提供了许多高效的并发编程模式,以满足日益增长的多核和分布式系统的需求。以下是一些常用的高效并发编程模式: 异步编程:使用std::async来创建异步任务,可以在后台执行任务,将结果返回给调用者。 并行编程&#…...
汇编语言作业(五)
目录 一、实验目的 二、实验内容 三、实验步骤以及结果 四、实验结果与分析 五、 实验总结 一、实验目的 1.熟悉掌握汇编语言的程序结构,能正确书写数据段、代码段等 2,利用debug功能,查看寄存器(CS,IP,AX,DS..)及数据段的…...
收音机的原理笔记
1. 收音机原理 有线广播:我们听到的声音是通过空气振动进行传播,因此可以通过麦克风(话筒)将这种机械振动转换为电信号,传到远处,再重新通过扬声器(喇叭)转换为机械振动,…...
排序算法案例
排序算法概述 排序算法是计算机科学中的一个重要主题,用于将一组数据按特定顺序排列。排序算法有很多种,每种算法在不同情况下有不同的性能表现。不同的排序算法适用于不同的场景和数据特征。在选择排序算法时,需要考虑数据规模、数据分布以…...
时间序列评价指标
评价指标 均方误差( M S E MSE MSE) 定义:预测值与实际值之间差异的平方和的平均值。公式: ( M S E 1 n ∑ i 1 n ( y i − y ^ i ) 2 ) (MSE \frac{1}{n}\sum_{i1}^{n}(y_i - \hat{y}_i)^2) (MSEn1∑i1n(yi−y^i)…...
Docker:安装 Orion-Visor 服务器运维的技术指南
请关注微信公众号:拾荒的小海螺 博客地址:http://lsk-ww.cn/ 1、简述 Orion-Visor 是一种用于管理和监控容器的工具。它提供了一个直观的界面,用于查看容器的状态、资源使用情况以及日志等信息。在这篇技术博客中,我们将介绍如何…...
HarmonyOS Next 系列之底部标签栏TabBar实现(三)
系列文章目录 HarmonyOS Next 系列之省市区弹窗选择器实现(一) HarmonyOS Next 系列之验证码输入组件实现(二) HarmonyOS Next 系列之底部标签栏TabBar实现(三) 文章目录 系列文章目录前言一、实现原理二、…...
mac怎么录制屏幕?这2个方法你值得拥有
在数字化时代,屏幕录制已经成为一种常见且重要的工具,无论是教学演示、游戏直播还是会议记录,屏幕录制都发挥着不可或缺的作用。对于Mac用户而言,如何高效、便捷地进行屏幕录制,是一个值得探讨的话题,可是很…...
爱德华三坐标软件ACdmis.AC-dmis密码注册机
爱德华三坐标软件 AC-DMIS 是一款功能强大的三坐标测量软件,具有以下特点: • 支持多种测量模式:包括接触式测量、非接触式测量、复合式测量等,可以满足不同类型工件的测量需求。 • 高精度测量:采用先进的测量算法和…...
计算机网络 期末复习(谢希仁版本)第3章
对于点对点的链路,目前使用得最广泛的数据链路层协议是点对点协议 PPP (Point-to-Point Protocol)。局域网的传输媒体,包括有线传输媒体和无线传输媒体两个大类,那么有线传输媒体有同轴电缆、双绞线和光纤;无线传输媒体有微波、红…...
代码随想录——数组
给定一个n个元素有序(升序)的整型数组nums和一个目标值target,写一个函数搜索nums中的target,如果目标值存在返回下标,否则返回-1. //这个题说实话从逻辑上来看实在是太简单了,但是为什么每一次我写起来都感…...
计算机网络7——网络安全4 防火墙和入侵检测
文章目录 一、系统安全:防火墙与入侵检测1、防火墙1)分组过滤路由器2)应用网关也称为代理服务器(proxy server), 二、一些未来的发展方向 一、系统安全:防火墙与入侵检测 恶意用户或软件通过网络对计算机系统的入侵或攻击已成为当今计算机安…...
html+CSS+js部分基础运用20
根据下方页面效果如图1所示,编写程序,代码放入图片下方表格内 图1.效果图 <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta http-equiv"X-UA-Compatible" conte…...
ISO 19115-2:2019 附录C XML 模式实现
C.1 XML 模式 本文件中定义的 UML 模型的 XML 模式在 ISO/TS 19115-3 中定义的适当 XML 命名空间中提供。新增内容包括: 命名空间前缀模式文件名Metadata for ACquisition (mac)acquisitionInformationImagery.xsdMetadata for Resource Content (mrc)contentInfo…...
天河定制型网站建设/西安seo优化排名
小编典典关于使用FileReader的一般注意事项:FileReader在内部使用FileInputStream,它会覆盖finalize()并且因此不建议使用它对垃圾回收的影响,尤其是在处理大量文件时。除非您使用的是Java 7之前的Java版本,否则应改用java.nio.fi…...
做网站建设/买卖平台
眼下,HR们最大的痛苦和麻烦之一,便是企业优秀人才频繁跳槽的问题:从一线业务精英到总部技术骨干,从行政人事主管到财务审计专员,从封疆大吏到总监诸候们……似乎都在导演一场跳槽和转行风暴。而且,这股风似…...
济南做html5网站建设/百度seo什么意思
项目场景:python使用pymysql import pymysql# 建立数据库连接 conn pymysql.connect(hostlocalhost,port3306,userroot,password,charsetutf8 ) print(conn) # 获取游标 cursor conn.cursor() print(cursor)问题描述: 在pycharm连接的时候明明之前连…...
国际网站哪里做/青岛seo杭州厂商
vue双向绑定源码解析1、概念监听器 Observer:用来劫持并监听所有属性,如果属性发生变化,就通知订阅者;订阅器 Dep:用来收集订阅者,对监听器Observer和 订阅者Watcher进行统一管理;订阅者 Watche…...
受欢迎的大连网站建设/实时军事热点
我们辛辛苦苦做一个网站不容易,一不留神还会被搜索引擎清0给k了,难道搜索引擎给清0了,我们就放弃吗,那样的话也太伤心了。下面我就来谈谈被搜索引擎k的几种类型及处理方式。一\ 大量的网站同一时间被k如果你的网站被k了࿰…...
个人网站不备案做经营性质网站/上海网站推广广告
为了我们电脑的安全,一般我们都会给电脑设置开机密码,这样对电脑来说就比较安全了。但是,每次开机都的输入密码才可以进入系统桌面,这样比较麻烦,而且还浪费时间;想取消开机密码,但不知道怎么取…...