C语言进阶 - 指针练习-1

2023-04-27 21:12:32 浏览数 (1)

前言

考察对数组名、指针运算、指针类型的理解。

数组名的意义:

  1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。
  2. &数组名,这里的数组名表示整个数组,取出的是整个数组的地址。
  3. 除此之外所有的数组名都表示首元素的地址。

1. 一维数组

代码语言:javascript复制
#include <stdio.h>

int main() {
	//一维数组
	int a[] = { 1,2,3,4 };
	int i = 1;
	printf("%-2d -- %dn", i  , sizeof(a));
	//数组名a单独出现在sizeof内部,表示整个数组,求出的是整个数组的大小 -- 16

	printf("%-2d -- %dn", i  , sizeof(a   0));
	//数组名a没有单独出现,表示的是数组首元素的地址,大小为 -- 4(或8)

	printf("%-2d -- %dn", i  , sizeof(*a));
	//a是数组名,表示数组首元素的地址,即&a[0],解引用*之后就是数组首元素a[0],大小是 -- 4

	printf("%-2d -- %dn", i  , sizeof(a   1));
	//	a是数组名,表示数组首元素的地址,   1表示跳过一个int元素,
	//(a   1)表示a[1]的地址,大小是-- 4(或8)

	printf("%-2d -- %dn", i  , sizeof(a[1]));
	//数组首元素,大小为 -- 4

	printf("%-2d -- %dn", i  , sizeof(&a));
	//a是数组名,&a表示取出了整个数组的地址,类型是数组指针,大小为 -- 4(或8)

	printf("%-2d -- %dn", i  , sizeof(*&a));
	//	a是数组名,& a表示取出了整个数组的地址,类型是数组指针。
	//  *解引用表示找到了整个数组,所以计算的是整个数组的大小-- 16

	printf("%-2d -- %dn", i  , sizeof(&a   1));
	//	a是数组名,& a表示取出了整个数组的地址,类型是数组指针。
	//	数组指针 1将跳过整个数组的大小,指向下一个数组,仍然是指针 大小 -- 4(或8)

	printf("%-2d -- %dn", i  , sizeof(&a[0]));
	//是a[0]的地址,大小 -- 4(或8)

	printf("%-2d -- %dn", i  , sizeof(&a[0]   1));
	//是a[1]的地址,大小 -- 4(或8)

	return 0;
}

运行结果:

2. 字符数组

代码语言:javascript复制
#include <stdio.h>

int main() {
	//字符数组
	char arr[] = { 'a','b','c','d','e','f' };

	printf("%dn", sizeof(arr));
	//arr是数组名,单独出现在sizeof内部,表示整个数组,计算的是整个数组的大小 -- 6

	printf("%dn", sizeof(arr   0));
	//arr是数组名,表示首元素的地址, 0表示跳过0个元素,仍然是首元素的地址 -- 4(或8)

	printf("%dn", sizeof(*arr));
	//arr是数组名,表示首元素的地址,*解引用之后表示首元素arr[0],大小 -- 1

	printf("%dn", sizeof(arr[1]));
	//数组元素arr[1]的大小 -- 1

	printf("%dn", sizeof(&arr));
	//&arr表示取到了整个数组的地址,本质上是数组指针(char (*)[6]), 大小 -- 4(或8)

	printf("%dn", sizeof(&arr   1));
	//&arr表示取到了整个数组的地址, 1后将跳过整个数组的大小,
	//得到的新地址是另一个数组的地址。 大小 -- 4(或8)

	printf("%dn", sizeof(&arr[0]   1));
	//&arr[0]得到数组元素arr[0]的地址, 1后得到数组元素arr[1]的地址。大小 -- 4(或8)

	//---------------------------------------------------------
	printf("%dn", strlen(arr));
	//strlen()函数计算的是字符串,''是结束标志。字符数组arr没有''出现,该函数计算时
	//不知道何时停止,越出数组arr的有效范围(越界)后在某一个''处停下来,
	//计算的值是 -- 随机值。

	printf("%dn", strlen(arr   0));
	//同上 -- 随机值

	printf("%dn", strlen(*arr));//-->strlen(97)
	//arr是数组名,是数组首元素的地址。*解引用之后是数组首元素arr[0],
	//而strlen接收的是const char*的指针。将会把arr[0]类型转换为指针后传入strlen函数,
	//arr[0]的值是97,这个程序并没有通过地址97来开辟空间,地址97相当于野指针,
	//导致程序出错

	printf("%dn", strlen(arr[1]));
	//同上,只不过把数组第二个元素当做地址传入strlen,程序也会出错。

	printf("%dn", strlen(&arr));
	//&arr取出的是整个数组的地址,本质是一个数组指针(char(*)[6]),数值上等于数组名。
	//传入strlen后被转换为const char*类型,指向的还是数组首元素大小。 -- 随机值
	
	printf("%dn", strlen(&arr   1));
	//&arr取出的是整个数组的地址,本质是一个数组指针(char(*)[6])。
	// 1后跳过整个数组的大小,指向了下一个数组。
	//传入strlen后被转换为const char*类型,指向的还是下一个数组的首元素。 大小-- 随机值-6

	printf("%dn", strlen(&arr[0]   1));
	//&arr[0]取出的是数组首元素的地址, 1之后指向数组第二个元素的地址:&arr[1]
	//大小 -- 随机值-1

	return 0;
}

3. 字符串

代码语言:javascript复制
#include <stdio.h>

int main() {
	char arr[] = "abcdef";

	printf("%dn", sizeof(arr));
	//表示整个数组。 大小 -- 7

	printf("%dn", sizeof(arr   0));
	//表示数组首元素的地址。 大小 -- 4(或8)

	printf("%dn", sizeof(*arr));
	//arr表示数组首元素地址,*arr表示数组首元素arr[0]。大小 -- 1

	printf("%dn", sizeof(arr[1]));
	//数组第二个元素。大小 -- 1

	printf("%dn", sizeof(&arr));
	//&arr表示整个数组的地址,本质是数组指针。 大小 -- 4(或8)

	printf("%dn", sizeof(&arr   1));
	//&arr表示整个数组的地址,本质是数组指针。
	//&arr 1跳过一个数组的大小,表示下一个整个数组的地址。大小 -- 4(或8)

	printf("%dn", sizeof(&arr[0]   1));
	//&arr[0]表示数组首元素的地址。
	//&arr[0] 1跳过一个int元素,表示数组第二个元素的地址。大小 -- 4(或8)

	//----------------------------------------------------
	
	printf("%dn", strlen(arr));
	//strlen函数计算''之前的字符个数。
	//arr表示数组首元素的地址。大小 -- 6

	printf("%dn", strlen(arr   0));
	//arr表示数组首元素的地址。
	//arr 0表示跳过0个char类型的元素。大小 -- 6

	printf("%dn", strlen(*arr));
	//arr是数组名,是数组首元素的地址。*解引用之后是数组首元素arr[0],
	//而strlen接收的是const char*的指针。将会把arr[0]类型转换为指针后传入strlen函数,
	//arr[0]的值是97,这个程序并没有通过地址97来开辟空间,地址97相当于野指针,
	//导致程序出错

	printf("%dn", strlen(arr[1]));
	//同上,只不过把数组第二个元素当做地址传入strlen,程序也会出错。

	printf("%dn", strlen(&arr));
	//&arr取出的是整个数组的地址,本质上是数组指针,数值上等于数组名即数组首元素的地址。
	//传入strlen函数后由数组指针(char(*)[7])转换为字符指针(char*),指向的还是数组首元素。
	// 大小 -- 6

	printf("%dn", strlen(&arr   1));
	//&arr取出的是整个数组的地址,本质上是数组指针,数值上等于数组名即数组首元素的地址。
	//&arr 1表示跳过整个数组的大小,指向下一个同类型数组。
	//传入strlen函数后由数组指针(char(*)[7])转换为字符指针(char*),指向的还是数组首元素。
	//但下一个数组元素具体是什么并不知道,所以大小 -- 随机值。

	printf("%dn", strlen(&arr[0]   1));
	//&arr[0]表示arr[0]的地址。
	//&arr[0] 1表示跳过一个字符元素,指向arr[1]的地址。大小 -- 5

	return 0;
}

4. 字符指针

代码语言:javascript复制
#include <stdio.h>

int main() {
	char* p = "abcdef";

	printf("%dn", sizeof(p));
	//字符指针。大小 -- 4(或8)

	printf("%dn", sizeof(p   1));
	//p表示字符指针,指向字符'a'。
	//p 1跳过一个字符,指向字符'b'。大小 -- 4(或8)

	printf("%dn", sizeof(*p));
	//p表示字符指针,指向字符'a'。
	//*p表示字符'a'。大小 -- 1

	printf("%dn", sizeof(p[0]));
	//p[0] <=> *(p 0) <=> *p
	//其实是字符'a'。大小 -- 1

	printf("%dn", sizeof(&p));
	//p表示字符指针,指向字符'a'。
	//&p表示取出一级字符指针的地址,本质是二级指针。大小 -- 4(或8)

	printf("%dn", sizeof(&p   1));
	//p表示字符指针,指向字符'a'。
	//&p表示取出一级字符指针的地址,本质是二级指针。
	//&p 1即是二级指针 1,跳过一个字符指针,仍然是一个二级指针。
	//大小 -- 4(或8)

	printf("%dn", sizeof(&p[0]   1));
	//&p[0]表示字符'a'的地址。
	//&p[0] 1表示跳过字符'a',指向下一个字符'b'。
	//大小 -- 4(或8)

	printf("%dn", strlen(p));
	//p是字符指针,指向了字符串的首字符'a'。
	//大小 -- 6

	printf("%dn", strlen(p   1));
	//p是字符指针,指向了字符串的首字符'a'。
	//p 1表示跳过了一个字符,指向了下一个字符'b'。
	//大小 -- 5

	printf("%dn", strlen(*p));
	//p是字符指针,指向了字符串的首字符'a'。
	//*p表示字符'a',相当于把字符'a'当做地址传入strlen函数,
	//但该地址97并没有在程序中开辟相应内存空间,相当于野指针。
	//导致内存读写错误,程序崩溃。

	printf("%dn", strlen(p[0]));
	//原因同上

	printf("%dn", strlen(&p));
	//p是字符指针,指向了字符串的首字符'a'。
	//&p表示取出一级字符指针的地址,本质是二级指针。
	//传递给strlen函数的是一个二级指针,被转换为const char*指针,
	//指向的内容是未知的。 大小 -- 随机值。

	printf("%dn", strlen(&p   1));
	//p是字符指针,指向了字符串的首字符'a'。
	//&p表示取出一级字符指针的地址,本质是二级指针。
	//&p 1表示跳过一个一级字符指针,指向了下一个一级字符指针。
	//传递给strlen函数的是一个二级指针,被转换为const char*指针,
	//指向的内容是未知的。 大小 -- 随机值。

	printf("%dn", strlen(&p[0]   1));
	//&p[0]表示字符'a'的地址。
	//&p[0] 1表示跳过字符'a'的地址,即是字符'b'的地址。
	//大小 -- 5
	return 0;
}

5. 二维数组

代码语言:javascript复制
#include <stdio.h>

int main() {
	//二维数组 可以看成是由多个一维数组共同组成的
	int a[3][4] = { 0 };

	printf("%dn", sizeof(a));
	//a单独出现在sizeof内部,表示整个二维数组,计算的是整个二维数组的大小。 -- 48

	printf("%dn", sizeof(a[0][0]));
	//a[0][0] <=> *(a[0] 0) <=> *(* (a   0)   0)
	//表示二维数组行下标是0,列下标是0的元素。大小 -- 4

	printf("%dn", sizeof(a[0]));
	//a[0] <=> *(a 0) <=> *a。
	//a是二维数组的数组名,表示二维数组首元素的地址,也就是二维数组第一行一维数组的地址。
	//本质是一个数组指针(int(*)[4])。
	//a 0表示跳过0个数组的大小。
	//*a表示二维数组的第一行,即一个一维数组,也就是一维数组名,单独出现在sizeof内部,
	// 表示整个一维数组
	//大小 -- 16

	printf("%dn", sizeof(a[0]   1));
	//a[0]是一维数组名,即二维数组中的一维数组首元素的地址。
	//a[0] 1表示跳过一个一维数组的元素,是一维数组第二个元素的地址。
	//大小 -- 4(或8)

	printf("%dn", sizeof(*(a[0]   1)));
	//a[0] 1表示跳过一个一维数组的元素,是一维数组第二个元素的地址。
	//*(a[0] 1)表示一维数组的第二个元素。或者说是二维数组中行下标为0,列下标为1的元素。
	//大小 -- 4

	printf("%dn", sizeof(a   1));
	//a是二维数组的数组名,表示二维数组首元素的地址,也就是二维数组第一行一维数组的地址。
	//本质是一个数组指针(int(*)[4])。
	//a 1表示跳过一个一维数组的大小,是下一个整个一维数组的地址。即第二个一维数组的地址&a[1]。
	//大小 -- 4(或8)

	printf("%dn", sizeof(*(a   1)));	
	//a 1表示跳过一个一维数组的大小,是下一个整个一维数组的地址。即第二个一维数组的地址。
	//*(a 1)表示第二个一维数组,也就是第二个一维数组的数组名a[1],数组名单独出现在sizeof内部,
	// 表示整个一维数组,计算的是整个一维数组的大小。
	//大小 -- 16

	printf("%dn", sizeof(&a[0]   1));
	//&a[0] 对第一行数组名取地址,得到的是第一行一维数组的地址,
	//&a[0] 1 得到的是第二行一维数组的地址。
	//大小 -- 4(8)

	printf("%dn", sizeof(*(&a[0]   1)));
	//*(&a[0]   1) 对第二行一维数组地址解引用,得到第二行,计算的是第二行的大小。
	//大小 -- 16

	printf("%dn", sizeof(*a));
	//a是二维数组的数组名,表示二维数组首元素的地址,也就是二维数组第一行一维数组的地址。
	//*a表示拿到了第一行的一维数组,相当于一维数组的数组名,数组名单独出现在sizeof内部,
	//计算的是整个一维数组的大小。 -- 16

	printf("%dn", sizeof(a[3]));
	//若二维数组真的有第四行的一维数组,那么数组名就是a[3],
	//数组名单独出现在sizeof内部,计算的是整个一维数组的大小。
	//虽然该二维数组并没有a[3],但此处a[3]并没有越界访问,因为sizeof是根据类型来计算
	//大小的,a[3]的类型不越界访问就知道。

	return 0;
}

END

0 人点赞