草庐IT

C语言指针进阶(下)

长月. 2023-07-13 原文

提示: 本篇深度剖析数组和指针的知识点,并且列举多种例子来说明sizeof和strlen的用法
接下来一起来学习吧👻👻

文章目录


前言

九、数组和指针

数组–>能够存放一组相同类型的元素,数组的大小取决于数组的元素个数和元素类型
指针–>就是地址或者也说是指针变量,大小是4/8个字节
二者之间的关系:
(1)数组是数组,指针是指针,二者不等价
(2)数组名是数组首元素的地址,这个地址可以存放在指针变量中
(3)我们可以用指针来遍历数组
(4)数组名
大多数情况下,数组名是数组首元素的地址.
但是有两个例外:
一是sizeof(数组名)–>数组名表示整个数组,计算的是整个数组的大小
二是&数组名–>数组名表示整个数组,取出的是数组的大小

1.透彻理解整型数组

以下内容的重点是区分下面三种写法的区别是什么以及sizeof和strlen在这三种写法中的使用

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main() {
	int a[] = { 1,2,3,4 };
	printf("%d\n", sizeof(a));//16
	//一个整型是四个字节,sizeof(数组名)就是例外情况之一,计算的是数组总大小,单位是字节,所以是16

	printf("%d\n", sizeof(a + 0));//4
	//注意X86环境32位,X64环境64位,目前是X86环境
	//sizeof(a+0)不是把数组名单独放在siaeof内部,所以这里的a表示数组名首元素的地址
	//a+0其实是数组首元素的地址
	//首元素的地址+0还是首元素的地址,大小是首元素地址的大小,4(X86环境)/8(X64环境)个字节

	printf("%d\n", sizeof(*a));//4
	//不是数组名单独放在sizeof内部,所以这里的a表示数组首元素的地址,a等价于&a[0]
	//*a等价于*&a[0]等价于a[0]
	//首元素的大小也就是一个整型的大小4

	printf("%d\n", sizeof(a + 1));//4/8
	//不是数组名单独放在sizeof内部,所以这里的a表示数组首元素的地址,a的类型是int*
	//a+1  跳过一个整型,是第二个元素的地址.是地址的话就是4/8个字节


	printf("%d\n", sizeof(a[1]));//4
	//数组下标为1的元素的大小,数组每个元素都是整型,大小为4

	printf("%d\n", sizeof(&a));//4/8
	//&a 取出的是整个数组的地址,是地址就是4个或者8个字节,即使它是整个数组的地址也仅仅是个地址!!!
	//&a 要是想存起来,需要放到一个数组指针里面
	//int (*pa)[4]=&a;  这里&a的类型是int (*)[4]

	printf("%d\n", sizeof(*&a));//16
	//&a 拿到整个数组
	//*&a  解引用整个数组
	//整个数组的大小是4*4=16字节
	//事实上,*和&可以相互抵消,在这里sizeof(*&a)等价于sizeof(a),也就是整个数组的大小16

	printf("%d\n", sizeof(&a + 1));//4/8
	//&a  拿到整个数组的地址,它的类型是数组指针int (*)[4]
	//&a+1  数组指针+1指的是地址跳过一个数组的,但是其实它还是指向内存里面的,是地址就是4/8个字节

	printf("%d\n", sizeof(&a[0]));//4/8
	//取出首元素的地址 4/8个字节

	printf("%d\n", sizeof(&a[0] + 1));//4/8
	//第二个元素的地址
}

图解:

2.透彻理解字符数组(区分sizeof和strlen)

重点:区分sizeof和strlen

sizeof()👻👻👻
1.sizeof计算的是占用内存空间的大小,单位是字节,不关注内存中到底存放的是什么
2.注意sizeof不是函数,是操作符
strlen()👻👻👻
1.strlen是函数
2.strlen是针对字符串的,求的是字符串的长度,本质上统计的是\0之前出现的字符个数

(1)sizeof和strlen在字符数组中的应用

定义一个字符数组
char arr[] = { ‘a’,‘b’,‘c’,‘d’,‘e’,‘f’ };

sizeof用法:
printf("%d\n", sizeof(arr));//6

sizeof(数组名) 数组名表示整个数组的地址
sizeof计算的是占用内存空间的大小,单位是字节,不关注内存中到底存放的是什么
sizeof(arr) 计算整个数组的大小,6个字符型元素总大小为6字节

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

数组名没有单独放在sizeof内部,这里是首元素的地址
arr+0 还是数组首元素的地址
不管是什么地址,只要是地址就是4/8个字节

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

这里的arr是首元素地址
arr是首元素,计算的是首元素的大小
数组名的类型是char
即数组里面每个元素的类型都是char*
这里的arr是首元素的地址,解引用,也就是char*类型的解引用,访问一个字节

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

arr[1]是数组的第二个元素,一个字符它的大小为1个字节

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

&arr取出的是数组的地址
数组的地址也是地址,为4/8个字节

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

&arr 数组的地址 +1 代表跳过一个数组后的地址
但是它还是一个地址,地址的长度为4/8个字节

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

&arr[0] 下边为0的元素的地址 +1 跳过这个元素的地址
实质上是第二个元素的地址,但还是地址,为4/8个

strlen的用法
printf("%d\n", strlen(arr));//随机值

arr指向首元素的地址
strlen是针对字符串的,求的是字符串的长度,本质上统计的是\0之前出现的字符个数
\0之前是多少个字符,长度就是多少,strlen会一直往后数,直到遇到\0停止
但是不知道会什么时候遇到\0,所以这个长度是个随机值

printf("%d\n", strlen(arr + 0));//随机值

arr指向首元素的地址 +0 还是指向首元素的地址
传进来首元素的地址,strlen会一直往后数,直到遇到\0停止
但是不知道会什么时候遇到\0,所以这个长度是个随机值

printf("%d\n", strlen(*arr));//非法访问

在之前的学习中,模拟实现strlen功能的函数是这么写的:
my_strlen(const char* str){}
注意传给strlen的是地址,arr指向首元素的地址,解引用得到首元素’a’,所以传进去的是字符a,而字符a的本质是97
把97传给strlen,strlen就把97当成一个地址,所以strlen就从97这个地址编号往后数,97作为地址编号找到的内存空间,不是给我们分配的内存空间,97是我们随便传入的一个地址,就要去访问它吗?这样是不行的
所以这里会形成非法访问的

printf("%d\n", strlen(arr[1]));//非法访问

arr[1]是字符b,这里会把b的ASCII值当成地址,b–98,同上会形成非法访问

printf("%d\n", strlen(&arr));//随机值

&arr是数组的地址,但传给strlen之后还是从数组的起始位置开始往后找\0,它数到的也是随机值

printf("%d\n", strlen(&arr + 1));//随机值-6

&arr+1 跳过整个数组,然后往后数找\0,也不知道什么时候能遇到\0,结果也是个随机值
但是这个随机值一定比从数组原始位置开始往后数时得到的随机值小6,因为开始的位置不同

printf("%d\n", strlen(&arr[0] + 1));//随机值-1

是从第二个元素的地址开始往后数的,往后数找\0,也不知道什么时候能遇到\0,结果也是个随机值
但是这个随机值一定比从数组原始位置开始往后数时得到的随机值小1,因为开始的位置不同

(2)sizeof和strlen在用字符串初始化数组中的应用

用字符串初始化数组:
char arr[] = “abcdef”;

[0] a
[1] b
[2] c
[3] d
[4] e
[5] f
[6] \0
在数组里面实际上放了7个字符

sizeof用法
printf("%d\n", sizeof(arr));//7

arr单独放在sizeof内部,sizeof计算的是整个数组的大小,关心的数组的大小,不关心里面是不是\0
所以它的大小是7

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

arr是首元素的地址,首元素的地址+0,还是首元素的地址,是地址就是4个或者8个字节

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

arr是首元素的地址,arr 是数组首元素,每个元素都是char类型,每个元素的大小都是一个字节
补充:首元素可以怎么表示?
arr[0]或者
arr或者*(arr+0)
计算数组的大小时,可以写成:
int sz=sizeof(arr)/sizeof(arr[0];
int sz=sizeof(arr)/sizeof(*arr);

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

arr[1]就是第二个元素的大小
数组每个元素都是char类型,每个元素的大小都是一个字节

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

&arr取出的是整个数组的地址,是地址,它的长度就是4或者8个字节

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

&arr取出的是整个数组的地址 +1 跳过整个数组之后的地址
是地址就是4/8个字节
注意:与之前I.里面跳过整个数组的地址,在跳过的内容上有所区别,之前跳过整个数组的时候数组里面没有\0.这次跳过的数组里面包含\0

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

&arr[0] 取到的是第一个元素的地址,+1 是跳过第一个元素后的地址
是地址,就是4/8个字节

strlen用法
printf("%d\n", strlen(arr));//6

arr是首元素的地址,strlen从首元素的地址开始往后数找\0,\0前面有6个元素,长度为6

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

arr数组名表示首元素的地址 +0 还是首元素的地址
strlen从首元素的地址开始往后数找\0,\0前面有6个元素,长度为6

printf("%d\n", strlen(*arr));//非法访问

*arr 是第一个元素a的值传给strlen,当成地址去访问会造成非法访问

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

&arr 整个数组的地址
&arr的类型是数组指针char(*)[7]
而实际上strlen应该穿进去的是const char 类型的指针(地址),在这里的话非要传的类型是数组指针,这时就会把它强制转换成const char类型的
在这里编译的时候会报警告,但是不影响使用
strlen数的时候还是从起始的位置开始数,直到遇到\0,长度应该为6

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

&arr[0] 首元素的地址 +1 跳过首元素的地址 往后数直到遇到\0.可以数到5个

注意:
strlen()进去的应该是地址,不应该是元素,如果传进去元素,会把元素的值当成地址进行访问,造成非法访问

(3)当把常量字符串的首地址放进指针变量,sizeof和strlen的用法

char* p = “abcdef”;

sizeof:
printf("%d\n", sizeof(p));//4/8

这里算的是一个指针变量的大小,既然是指针变量,指针变量是用来存放地址的,所以指针变量的大小是4或者8

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

p里面是常量字符串的首地址也就是a的地址,p+1 p的类型是char*,char*类型的+1跳过一个字符,实际上也就是字符b的地址
是地址,就是4个或者8个字节

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

p存放的是常量字符串的首地址也就是a的地址,解引用访问一个字符,一个字符的大小就是1

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

p[0]从数组的访问形式可以转成指针
p[0]可以写成*(p+0),也就是*p
p存放的是常量字符串的首地址也就是a的地址,解引用访问一个字符,一个字符的大小就是1

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

&p 拿到的是地址,是地址长度就是4/8个字节
不过要清楚的是&p是指针变量p的地址,而不是常量字符串的地址
&p是个二级指针

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

p类型char*
&p类型char**
char* p;//字符指针跳过一个字符
char* pp=&p; //(第二个说明pp是指针,第一个说明pp里面指向的是char类型的数据)pp指向的是char的数据,+1跳过一个char的数据
但是还是地址,所以是四个或者八个字节

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

&p[0]取出a的地址,+1跳过a的地址,是字符b的地址
但还是地址,是地址就是四个或者八个字节

strlen的用法
printf("%d\n", strlen(p + 1));//5

p+1 跳过a的地址,里面放的是b的地址,从b开始往后数,字符串末尾是\0,所以长度是5

printf("%d\n", strlen(*p));//非法访问

*p是a,传过去但是strlen需要的是地址,那就把a的ASCII码值当做地址,形成了非法访问

printf("%d\n", strlen(p[0]));//非法访问

p[0]和p是一样的,因为p[0]等价于(p+0),都是a,传过去但是strlen需要的是地址,那就把a的ASCII码值当做地址,形成了非法访问

printf("%d\n", strlen(&p));//随机值x

注意&p拿出来的是哪里的地址,
拿出p的地址然后往后数,p里面存的地址是什么以及后面什么时候遇到\0这完全不可知
所以这里只能是随机值

printf("%d\n", strlen(&p + 1));//随机值y

&p+1 跳过p的地址往后数,什么时候遇到\0,这就更无法预测了,所以也是随机值
但是这个随机值y和上面的随机值x毫无关系,完全取决于这个内存块里面放的是什么

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

&p[0]+1 是b的地址 ,从b的地址往后数,遇到\0,所以长度是5

3.透彻理解二维数组

创建一个二维数组
int a[3] [4] = { 0 };

二维数组:
二维数组的首元素是第零行

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

a这个二维数组的数组名单独放在sizeof内部,计算整个数组的大小
这个二维数组三行四列,每个元素是整型,一个整型四个字节,434=48字节

printf("%d\n", sizeof(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/8

arr[0]数组名不是单独放在sizeof内部,a[0]表示表示首元素的地址,即第一行第一个元素的地址也就是a[0][0]的地址
+1 第一行第二个元素的地址即a[0][1]的地址
是地址就是4/8个字节

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

*(a[0]+1) 也就是解引用第一行第二个元素的地址,得到a[0][1] 大小是4个字节

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

a作为二维数组的数组名,并非单独放在sizeof内部,所以表示首元素的地址
二维数组的首元素是第一行,这里的a是第一行的地址,第一行的地址是数组指针int ()[4]
当+1的时候,跳过一行,
a+1 是第二行的地址,注意不是第二行首元素的地址,因为a的类型是数组指针int (
)[4],+1之后还是这个类型,是指向第二行的
要分清,第二行的地址是数组指针,第二行首元素的地址是整型指针

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

解读方式1:这里a+1拿到的是第二行的地址,第二行的地址解引用相当于对第二行的数组指针解引用也就是访问一个数组,访问第二行的大小,44=16字节
解读方式2:
(a+1)从语法上讲等价于a[1],a[1]是第二行的数组名,sizeof(a[1])数组名单独放到sizeof内部,求出来的是第二行的大小,4*4=16

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

&a[0] 数组名取地址,取出的是第一行的地址
+1 第二行的地址
是地址就是4/8个字节

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

上一个代码已解释&a[0] + 1是第二行的地址,解引用就是第二行,第二行的大小4*4=16
*(&a[0] + 1))等价于a[1]1

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

a在这里是首元素的地址,二维数组的首元素地址就是第一行的地址,解引用就是第一行,第一行的大小是4*4=16
*a 就是第一行
*a 等价于 *(a+0)等价于a[0]

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

这个数字总共只有三行,a[3]是第四行了,a[3]和a[2],a[1],a[0]同样的道理是行的数组名,如果有第四行的话,它的大小一定是16字节,因为每一行都是16字节
这里存在越界吗?
不存在.因为sizeof内部的表达式不会真的去访问或者计算
这里就根本不会去访问第四行,只要根据它的类型属性确定了,假设存在第四行的话,和之前的a[2],a[1],a[0比较一推断,就知道是相同的类型,不会形成越界访问

补充说明

int a = 5;
short s = 11;
printf("%d\n", sizeof(s = a + 2));//2
//这里按说a是整型,+2之后还是整型,非要把四个字节的整型数据放到2个字节的short变量里面,short变量不过也可以放下7,因为发生了截断,把低位的7留下,高位的0截断丢了,也可以计算出7
//在计算表达式的值所占的空间大小是几个字节,把结果放到short类型的变量里面,结果是short类型的,sizeof(short类型的数据)理论上应该是两个字节,是2
//s = a + 2值属性是7,类型属性是short

printf("%d\n", s);//11
//这里运行的结果是11而不是计算之后的7
//说明sizeof内部的表达式不会真的计算,
//原因一:因为sizeof通过类型就可以知道表达式的大小是2,根本不需要计算得出2
//原因二:代码test.c---->编译--->链接--->test.exe
//如果表达式s=a+2要运算的话必须生成可执行程序test.exe才能运算,遗憾的是像sizeof这样的在编译期间就已经处理了,编译期间根据类型属性就已经确定是2了,就不会把表达式计算了

int a = 10;
a + 3;
//像a+3这样的式子有值属性,类型属性
//值属性是13
//类型属性是int

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

a是第一行的地址,第一行的地址解引用,*a等价于a[0]
第一行的数组名a[0]表示首元素的地址&a[0][0],+1就是&a[0][0]+1=&a[0][1]
也就是第一行第二个元素的地址,是地址的话长度就是4/8个字节

注意点

1.数组名单独放到sizeof内部,这里的数组名表示整个数组,计算的是整个数组的大小
&数组名,这里的数组名表示整个数组,取出的是整个数组的地址
除上面两个例外情况,所有的数组名都表示首元素的地址
2.二维数组首元素的地址是第一行的地址,
✨sizeof(a[0]) 计算的是这一行的大小
✨sizeof(a[0]+1) 某一行的数组名并没有单独放到sizeof内部的时候,数组名表示首元素的地址指的是这一行的首元素的地址
简单来说就是降级处理:
当二维数组的数组名没有单独放在sizeof内部—>表示的是二维数组首元素的地址(是第一行的地址),如果某一行的数组名并没有单独放到sizeof内部的时候—>数组名表示首元素的地址指的是这一行的首元素的地址
3.sizeof只关注类型,不会计算里面的表达式


总结

指针进阶(下)的内容就到这里啦,创作不易😭如果对友友们有帮助的话,记得点赞收藏博客🥰🥰🥰,关注后续的指针进阶笔试题详解题目篇哦~🐾

有关C语言指针进阶(下)的更多相关文章

  1. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  2. ruby - 寻找通过阅读代码确定编程语言的ruby gem? - 2

    几个月前,我读了一篇关于ruby​​gem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:

  3. Unity 热更新技术 | (三) Lua语言基本介绍及下载安装 - 2

    ?博客主页:https://xiaoy.blog.csdn.net?本文由呆呆敲代码的小Y原创,首发于CSDN??学习专栏推荐:Unity系统学习专栏?游戏制作专栏推荐:游戏制作?Unity实战100例专栏推荐:Unity实战100例教程?欢迎点赞?收藏⭐留言?如有错误敬请指正!?未来很长,值得我们全力奔赴更美好的生活✨------------------❤️分割线❤️-------------------------

  4. 7个大一C语言必学的程序 / C语言经典代码大全 - 2

    嗨~大家好,这里是可莉!今天给大家带来的是7个C语言的经典基础代码~那一起往下看下去把【程序一】打印100到200之间的素数#includeintmain(){ inti; for(i=100;i 【程序二】输出乘法口诀表#includeintmain(){inti;for(i=1;i 【程序三】判断1000年---2000年之间的闰年#includeintmain(){intyear;for(year=1000;year 【程序四】给定两个整形变量的值,将两个值的内容进行交换。这里提供两种方法来进行交换,第一种为创建临时变量来进行交换,第二种是不创建临时变量而直接进行交换。1.创建临时变量来

  5. ruby 变量作为同一对象(指针?) - 2

    >>a=5=>5>>b=a=>5>>b=4=>4>>a=>5如何将“b”设置为实际的“a”,以便在示例中,变量a也将变为4。谢谢。 最佳答案 classRefdefinitializeval@val=valendattr_accessor:valdefto_s@val.to_sendenda=Ref.new(4)b=aputsa#=>4putsb#=>4a.val=5putsa#=>5putsb#=>5当您执行b=a时,b指向与a相同的对象(它们具有相同的object_id).当你执行a=some_other_thing时,a将指向

  6. ruby - 如何保持我不常用的编程语言技能 - 2

    关闭。这个问题是off-topic.它目前不接受答案。想改进这个问题吗?Updatethequestion所以它是on-topic用于堆栈溢出。关闭11年前。Improvethisquestion我不经常使用ruby​​-通常它加起来相当于每两个月或更长时间编写一次脚本。我的大部分编程都是使用C++进行的,这与ruby​​有很大不同。由于我与ruby​​之间的差距如此之大,我总是忘记语言的基本方面(比如解析文本文件和其他简单的东西)。我想每天练习一些基本的东西,我想知道是否有一些我可以订阅的网站,并且会向我发送当天的Ruby问题或类似的东西。有人知道这样的站点/Internet服务吗?

  7. ruby-on-rails - 如果特定语言环境中缺少翻译,如何配置 i18n 以使用 en 语言环境? - 2

    如果特定语言环境中缺少翻译,如何配置i18n以使用en语言环境翻译?当前已插入翻译缺失消息。我正在使用RoR3.1。 最佳答案 找到相似的question这里是答案:#application.rb#railswillfallbacktoconfig.i18n.default_localetranslationconfig.i18n.fallbacks=true#railswillfallbacktoen,nomatterwhatissetasconfig.i18n.default_localeconfig.i18n.fallback

  8. ruby-on-rails - 如何通过 URL 更改语言环境? - 2

    在我的双语Rails4应用程序中,我有一个像这样的LocalesController:classLocalesController用户可以通过此表单更改其语言环境:deflocale_switcherform_tagurl_for(:controller=>'locales',:action=>'change_locale'),:method=>'get',:id=>'locale_switcher'doselect_tag'set_locale',options_for_select(LANGUAGES,I18n.locale.to_s)end这有效。但是,目前用户无法通过URL更改

  9. ruby - 一种语言如何被自身解释(如 Rubinius)? - 2

    我使用Ruby编程已经有一段时间了,现在只使用Ruby的标准MRI实现,但我一直对我经常听到的其他实现感到好奇。前几天我在读有关Rubinius的文章,这是一个用Ruby编写的Ruby解释器。我试着在不同的地方查找它,但我很难弄清楚这样的东西到底是如何工作的。我在编译器或语言编写方面从来没有太多经验,但我真的很想弄明白。一门语言究竟如何才能被自己解释?编译中是否有一个我不明白这有意义的基本步骤?有人可以像我是个白痴一样向我解释这个吗(因为无论如何这都不会太离谱) 最佳答案 它比你想象的要简单。Rubinius并非100%用Ruby编

  10. ruby-on-rails - ruby 真的是一种完全面向对象的语言吗? - 2

    Ruby是完全面向对象的语言。在ruby​​中,一切都是对象,因此属于某个类。例如5属于Objectclass1.9.3p194:001>5.class=>Fixnum1.9.3p194:002>5.class.superclass=>Integer1.9.3p194:003>5.class.superclass.superclass=>Numeric1.9.3p194:005>5.class.superclass.superclass.superclass=>Object1.9.3p194:006>5.class.superclass.superclass.superclass.su

随机推荐