指针疑难杂症(进阶二)

1,关于常量字符串的探讨

先看一串代码

char arr1[] = "hello world!";
	char arr2[] = "hello world!";
	char* arr3 = "hello world!";
	char* arr4 = "hello world!";
	if (arr1 == arr2)
	
		printf("arr1 and arr2 are same\n");
	else
		printf("arr1 and arr2 are  not same\n");
	if(arr3==arr4)
		printf("arr3 and arr4 are same\n");
	else
		printf("arr1 and arr2 are not same\n");

代码的输出结果是这样的

arr1 and arr2 are  not same
arr3 and arr4 are same

常量字符串类似于“abcdef它是位于只读数据区,只能写不能改的,常量字符串只能存储一次,而上述的char*arr3 = "hello world!“其实只村粗了这个常量字符串的首元素的地址,而arr4也是一样,所以他们俩才会相等,因为直接是被常量字符串赋值的,但是arr1与arr2不一样,他们相当于各自开辟了新的空间,然后那一块空间上的字符串是"hello world”,虽然此时arr1与arr2都表示字符串首元素的地址,但是代表的是他们各自开辟空间的首元素的地址,这是不一样的,所以才会出现arr1 and arr2 are not same;
总结假设有一个常量字符串“abcdef”虽然我们看到的是"abcdef"但是在内存中存储的其实是a的地址也就是首元素的地址.

2,数组指针与指针数组如何辨别

int* arr1[10]; //arr1先于中括号结合表示此时arr1是一个数组,然后此时arr1的元素是int*整形指针所以此时的arr1是一个指针数组,本质还是数组,也就是整形指针数组
char *arr2[4];//arr2和arr1一样,先与中括号结合表示这是一个数组,然后数组的元素是char*所以此时的arr2表示的是一个字符数组 
char **arr3[5];//同理,只不过arr3的元素是char**表示的是字符二级指针,所以此时arr3表示的是二级指针数组
char (*arr4)[10]//表示的数组指针,此时arr4先于*结合表示此时arr4是一个指针,指向的是有10元素的数组,该数组每个元素是char
int (*arr5[10])[5]//arr5先于中括号结合表示这是一个数组,那么此时arr5数组的元素类型是什么?将arr5[10]盖住,剩下的就是改元素类型,该类型是int(*)[5]该类型是指向有五个ing数组的指针所以arr5的本质还是指针数组

3,关于二维数组的探究

二维数组首元素地址

如果有一个二维数组int arr[]2[5] = {1,2,3,4,5,6,7,8,9,10}
数组的arr也表示的是首元素的地址,但是如果是二维数组的话,那么其首元素的地址其实该二维数组的第一行也就是arr[0]五个元素的地址,并不是arr[0][0],虽然二者在地址大小的表示上也许都是一样的,但是本质上还是不同的

二维数组传参
void test(int arr[2][5])//可以
{}
void test(int arr[][])//不行
{}
void test(int arr[][5])//可以
{}
//总结:二维数组传参必须函数的形参最多省略第一个[]数字,第二个数字是不能省略的
// 个人理解:
// 虽然我们理解二维数组的时候,是用一个二维图理解的,将数组分成几行几列,
// 但是实际数组在内存中的存储是连续存储的,如果连第二个表示列的数组都省略了
// 那么编译器在编译的时候连什么时候该换行都不知道,但是行号不知道却可以,因为
// 行走完了,就没有了,那么便不需要行号也就是第一个数字了(以上仅仅是个人的理解觉得理解有大问题欢迎补充)
//
// 
// 当然二维数组除了可以传类似上面的,还可以传指针
//但是要知道二维数组传参传进去的是数组首元素的地址,而数组首元素的地址在二维数组中其实是第一行的地址
void test(int(*p)[5])//传进去的指针表示的是指向五个元素并且元素类型是int的指针,恰好和二维数组第一行所对应
{}

//

4, 函数指针的相关介绍

指向函数的指针

1,函数指针如何表示
int test(int x, int y) {}//int (*p)(int,int)      //*p表示p是一个指针,后面的圆括号表示此时p是一个函数指针,
                                               // 函数的形参类型是(int,int)返回类型也是int
void test2(int x){}//void(*ps)(int)       //*ps表示ps是一个指针,后面的圆括号表示此时的ps是一个函数指针
                                          //此时函数的形参类型是(int)返回类型是void

函数指针数组 在我看来其实和指针数组差不多,就是加[]的事情,例如上面的

如果int(*p[5])(int,int)那么此时p先与[]结合表示此时p是一个数组,将p[]盖住
表示的就是此时数组的元素类型,int(*)(int,int),和指针数组相似度极高

函数指针的简单应用

int test(int x, int y)
{
	return x + y;
}
int main()
{
	int(*p)(int, int) = &test;
	int c = p(2, 3);
	int d = (*p)(4, 6);
	printf("%d\n%d\n", c, d);
	int(*ps)(int, int) = test;
	int c1 = ps(2, 3);
	int d1 = (*ps)(4, 6);
	printf("%d\n%d", c1, d1);

	return 0;
}

剖析发现上述的运行结果都是一样的
所以其实函数名和数组相似,单独一个函数名表示的就是函数的地址,而函数指针的*在用指针调用函数的时候加不加其实没什么关系,但是我还是觉的加一下好,这样才能看出来他是一个指针hh

指针数组相关笔试题:

1,试题之前的补充

在这里插入图片描述

指针试题:

注意只要是指针,那么与编译器的环境有关,如果是在64平台下,那么指针的大小就是8如果是在32位平台下,那么其大小就是4,为了形象,我用的都是在64平台下操作的

int a[] = { 1,2,3,4 };
	printf("%d\n", sizeof(a));//16数组和整个sizeof连用表示的是整个数组,表示的并不是首元素地址
	printf("%d\n", sizeof(a + 0));//表示的是指针 未出现与sizeof与&那么此时a表示的首元素地址,地址+-也还是地址
	printf("%d\n", sizeof(*a));//4    a表示的是首元素地址,首元素地址解引用表示的就是首元素大小也就是int
	printf("%d\n", sizeof(a + 1));//表示的是指针    地址+-也还是地址
	printf("%d\n", sizeof(a[1]));//4    表示的是首元素
	printf("%d\n", sizeof(&a));//表示的是指针    只要加一个取地址并且前面没有解引用,那么就是指针
	printf("%d\n", sizeof(*&a));//16     
	//巧记:我们可以理解*和&的作用抵消了,那么表示的就是sizeof(a)
	//本质理解:&a此时表示的是int(*p)[4],加一个解引用的话此时表示的就是一个含有四个整形元素的数组,所以sizeof的值就是16
	printf("%d\n", sizeof(&a + 1));//表示的是指针     指针的加减依然还是指针
	printf("%d\n", sizeof(&a[0]));//指针
	printf("%d\n", sizeof(&a[0] + 1));//指针

//strlen计算的是'\0'前面元素的个数,而sizeof计算的就是你数组中元素个数的大小
	char arr[] = { 'a','b','c','d','e','f' };
	printf("%d\n", sizeof(arr));//6     
	printf("%d\n", sizeof(arr + 0));//指针
	printf("%d\n", sizeof(*arr));//1 
	printf("%d\n", sizeof(arr[1]));//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));//随机值(其实是不合法的)会报错  因为strlen要求传入的值地址,但此时传入的是该数组首元素,
	                            //表示的并不是地址,所以会报错
	printf("%d\n", strlen(arr[1]));//同上 报错
	printf("%d\n", strlen(&arr));//随机值   最后三个都不会报错,但是由于该字符没有'\0'并不知道在哪停止,所以会出现随机值
	printf("%d\n", strlen(&arr + 1));//随机值
	printf("%d\n", strlen(&arr[0] + 1));//随机值
char arr[] = "abcdef";//实际上这个字符串表示的是abcdef\0里面有七个元素
	printf("%d\n", sizeof(arr));//arr与sizeof连接,表示的是整个字符串
	printf("%d\n", sizeof(arr + 0));//指针
	printf("%d\n", sizeof(*arr));//1 表示该字符串的第一个元素
	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));//6因为此时的字符串是有'\0'的 所以strlen计算的就是\0前面的字符
	printf("%d\n", strlen(arr + 0));//6arr表示的是字符串首元素的地址,地址不论加减啥依旧还是地址,加0等于没加,所以还是6
	//printf("%d\n", strlen(*arr));//此时的*arr表示的是字符串首元素,会报错
	//printf("%d\n", strlen(arr[1]));//同上
	printf("%d\n", strlen(&arr));//6 该地址和字符串首元素地址的值是一样的,只不过表示的含义不一样
	                            //arr表示的是char元素的首地址
	                           //&arr表示的是char(*p)[7]是一个指向数组的指针
	printf("%d\n", strlen(&arr + 1));//此时跳过整个数组,所以是一个随机值
	printf("%d\n", strlen(&arr[0] + 1));//是数组的首元素加1  此时从该地址到\0有五个元素,所以是5

char* p = "abcdef";//此时p存储的就是该字符串首元素的地址
	printf("%d\n", sizeof(p));//指针
	printf("%d\n", sizeof(p + 1));//还是指针
	printf("%d\n", sizeof(*p));//1   首元素解引用代表的是a
	printf("%d\n", sizeof(p[0]));//1
	printf("%d\n", sizeof(&p));//指针的取地址还是一个指针,表示地址
	printf("%d\n", sizeof(&p + 1));//指针不管加减都是指针带下跟编译器所处平台大小有关
	printf("%d\n", sizeof(&p[0] + 1));//还是一个指针
	printf("%d\n", strlen(p));//6
	printf("%d\n", strlen(p + 1));//5
	//printf("%d\n", strlen(*p));//会报错,此时传进去的并不是一个地址而是一个元素
	//printf("%d\n", strlen(p[0]));//同上
	printf("%d\n", strlen(&p));//随机值,此时传进去的是p指针的地址,和字符串的地址无关
	printf("%d\n", strlen(&p + 1));//同上
	printf("%d\n", strlen(&p[0] + 1));//5  首元素地址加1变成第二个元素的地址
int a[3][4] = { 0 };
	printf("%d\n", sizeof(a));//表示的是整个整形数组 12*4 = 48
	printf("%d\n", sizeof(a[0][0]));//第一个元素 4
	printf("%d\n", sizeof(a[0]));//此时的a[0]与sizeof放在一起表示第一行元素 4 * 4 = 16
	printf("%d\n", sizeof(a[0] + 1));//此时的a[0]表示的是第一行首元素的地址,是一个指针
	                               //该指针类型是int*加1后还是指针
	printf("%d\n", sizeof(*(a[0] + 1)));//(a[0]+1)表示的是第一行元素中的第二个元素,此时解引用
	                                    //后表示的就是一个整形的大小        
	printf("%d\n", sizeof(a + 1));//表示的是数组首元素的地址加1还是指针,
	                              //但整个地址是代表第二行元素的地址
	                              //指针的类型是int(*p)[4]
	printf("%d\n", sizeof(*(a + 1)));//根据上述解释此时解引用表示的就是第二行元素的大小 4*4 = 16
	printf("%d\n", sizeof(&a[0] + 1));//地址
	printf("%d\n", sizeof(*(&a[0] + 1)));//(&a[0]+1)表示的就是第二行元素的地址,此时解引用表示的就是4*4 = 16
	printf("%d\n", sizeof(*a));//a表示的是首元素的地址,但是因为二维数组首元素代表的是第一行元素,所以此时解引用后也是16
	printf("%d\n", sizeof(a[3]));//按道理来说这个应该是越界了的	但是没关系
	           //假设又int a = 1;
			   //    计算sizeof(a)->sizeof(int)此时sizeof推导a是整形类型
	           //  而此时的sizeof(a[3])sizeof也会推导,其实就跟sizeof(a[0]),sizeof(a[1])一样此时的类型是int[4]
	           // sizeof不会真的去访问是否有a[3]这个元素的存在,只会推导,所以也还是不会报错的

	printf("%d\n", sizeof(a[4]));//同上

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
本系统的研发具有重大的意义,在安全性方面,用户使用浏览器访问网站时,采用注册和密码等相关的保护措施,提高系统的可靠性,维护用户的个人信息和财产的安全。在方便性方面,促进了校园失物招领网站的信息化建设,极大的方便了相关的工作人员对校园失物招领网站信息进行管理。 本系统主要通过使用Java语言编码设计系统功能,MySQL数据库管理数据,AJAX技术设计简洁的、友好的网址页面,然后在IDEA开发平台中,编写相关的Java代码文件,接着通过连接语言完成与数据库的搭建工作,再通过平台提供的Tomcat插件完成信息的交互,最后在浏览器中打开系统网址便可使用本系统。本系统的使用角色可以被分为用户和管理员,用户具有注册、查看信息、留言信息等功能,管理员具有修改用户信息,发布寻物启事等功能。 管理员可以选择任一浏览器打开网址,输入信息无误后,以管理员的身份行使相关的管理权限。管理员可以通过选择失物招领管理,管理相关的失物招领信息记录,比如进行查看失物招领信息标题,修改失物招领信息来源等操作。管理员可以通过选择公告管理,管理相关的公告信息记录,比如进行查看公告详情,删除错误的公告信息,发布公告等操作。管理员可以通过选择公告类型管理,管理相关的公告类型信息,比如查看所有公告类型,删除无用公告类型,修改公告类型,添加公告类型等操作。寻物启事管理页面,此页面提供给管理员的功能有:新增寻物启事,修改寻物启事,删除寻物启事。物品类型管理页面,此页面提供给管理员的功能有:新增物品类型,修改物品类型,删除物品类型。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

每天少点debug

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值