数组与指针题型解析(1)

引言

在初学编程语言时,我们经常容易被数组名和指针的实际表示含义混淆,本文将从一些数组与指针的笔试题入手,旨在弄明白它们在各种场景下表达的实际含义。

知识点补充

1. 数组名的含义:

(1)sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节。

(2)&数组名,这里的数组名表示整个数组,取出的是整个数组的地址,不是数组首个元素的地址。

除了这两种情况以外,数组名表示数组首元素的地址。

2. sizeof操作符:

sizeof操作符是C语言和C++语言中的一种特殊操作符,用于获取某个变量或类型的大小(占用的字节数)。它的作用是在编译时求得数据类型或变量的大小,而不是在运行时。

sizeof操作符可以用于以下方面:

  1. 获取基本数据类型的大小:可以使用sizeof操作符来获取int、float、char等基本数据类型的大小。例如,sizeof(int)将返回int类型的字节数,通常为4个字节。
  2. 获取数组的大小:sizeof操作符可以用于获取数组的大小,包括静态数组和动态数组。例如,sizeof(array)将返回数组array的总字节数,即元素个数乘以每个元素的大小。
  3. 获取指针的大小:sizeof操作符可以用于获取指针的大小,即指针所占的字节数。例如,sizeof(int*)将返回指针类型int*的字节数,通常为4或8个字节,这取决于系统的位数。
  4. 获取结构体和联合体的大小:sizeof操作符可以用于获取结构体和联合体的大小,即结构体或联合体的所有成员变量所占的总字节数。例如,sizeof(struct MyStruct)将返回结构体MyStruct的总字节数。

使用说明:

  1. sizeof操作符的结果是一个常量表达式,可以在编译时计算得到。
  2. sizeof操作符的结果是一个size_t类型的无符号整数。
  3. sizeof操作符的参数可以是变量名、类型名或表达式。
  4. sizeof操作符不能直接用于函数类型,但可以用于指向函数类型的指针。
  5. sizeof操作符的结果可能受到编译器和编译选项的影响,不同的编译器可能有不同的实现方式。

需要注意的是,sizeof操作符只是获取内存大小,而不是获取实际存储的数据大小。例如,对一个指针使用sizeof操作符,只会返回指针本身的大小,而不是它所指向的数据的大小。所以在使用sizeof操作符时,需要根据具体的需求选择合适的用法。

3. stelen函数:

strlen函数用于计算字符串的长度,即统计字符串中字符的个数。该函数属于C语言的标准库函数,位于头文件<string.h>中。

使用说明:

  1. 函数原型:size_t strlen(const char* str);
    参数str为要计算长度的字符串,返回值为字符串的长度。注意不应与保存字符串的数组大小相混淆。比如:char mystr[100]=“test string”,定义了一个大小为 100 个字符的字符数组,但初始化 mystr 的 C 字符串长度只有 11 个字符。 因此,sizeof(mystr) 的值是 100,而 strlen(mystr) 的返回值是 11。

  2. 参数说明:

    • str:要计算长度的字符串,可以是字符数组(如char str[100])或字符指针(如const char* str)。
  3. 返回值说明:

    • 返回值类型为size_t,即无符号整数类型。返回值为字符串中字符的个数(不包括字符串末尾的空字符’\0’)。
  4. 注意事项:

    • 传入的字符串必须以空字符’\0’结尾,否则函数会继续向后遍历直到遇到空字符。
    • 如果传入的字符串为空指针(即str为NULL),一般会导致程序崩溃或产生段错误。这是因为当传递NULL时,strlen函数会试图访问指向NULL的内存地址,而这是非法的操作。
  5. 示例代码:

    #include <stdio.h>
    #include <string.h>
    
    int main() {
        char str1[] = "Hello World";
        const char* str2 = "Hello, strlen!";
    
        printf("Length of str1: %zu\n", strlen(str1));
        printf("Length of str2: %zu\n", strlen(str2));
    
        return 0;
    }
    

    输出结果:

Length of str1: 11
Length of str2: 14

一维数组

题目实例:

#include<stdio.h>
int main() {
	//一维数组
	int a[] = {4,3,2,1,0};
	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));
	return 0;
}

运行结果(这个结果是基于vs2022 x64环境下运行的结果,不同编译环境最终的结果可能不同,这里仅做参考):

20
8
4
8
4
8
20
8
8
8

题目解释:

    int a[] = {4,3,2,1,0}; //一维数组,有5个int类型(4个字节)的元素
	printf("%d\n", sizeof(a)); // 20 这里数组名单独放在sizeof内部,这里的数组名a表示整个数组,计算的是整个数组的大小,共4*5=20字节
	printf("%d\n", sizeof(a + 0));// 4/8 a并非单独放在sizeof内部,也没有&,这里的a是数组首元素的地址,a+0还是数组首元素的地址。是地址就是4个字节(32位系统)或8个字节(64位系统)。
	printf("%d\n", sizeof(*a)); // 4 这里的a不是前面提到的两种特殊情况 ,*a==*(a+0)==a[0], *a就是数组的首元素,大小就是4字节。
	printf("%d\n", sizeof(a + 1));// 4/8 a并非单独放在sizeof内部,也没有&,所以数组名a是数组首元素的地址,a+1就是第二个元素的地址,这里a+1=&a[1]。是地址就是4或者8字节。
	printf("%d\n", sizeof(a[1]));// 4 a[1]表示数组第二个元素,大小是4字节。a[1]==*(a+1)。
	printf("%d\n", sizeof(&a)); // 4/8 &a表示整个数组的地址,并非是数组首元素的地址,不过由于其还是地址,所以还是4或者8个字节。
	printf("%d\n", sizeof(*&a));// 20 可以理解成*和&可以相互抵消,sizeof(*&a)可以看成sizeof(a)。
	//如果从本质理解,&a是一个数组指针类型,*&a就是对一个数组指针解引用访问一个数组的大小。
	//a是int*类型            int *str=a;  
	// &a是int(*)[5]类型     int (*str)[5]=&a;
	printf("%d\n", sizeof(&a + 1));// 4/8 &a是数组的地址,&a+1还是地址,表示数组a的下一个地址,是地址就是4/8个字节。
	printf("%d\n", sizeof(&a[0]));// 4/8 &a[0]是首元素的地址, 计算的还是地址的大小。
	printf("%d\n", sizeof(&a[0] + 1)); //4/8 &a[0] + 1是第二个元素的地址,计算地址的大小就是4或者8个字节。

字符数组

题目实例1:

#include<stdio.h>
#include<string.h>
int main() {
	char arr[] = { 'a','b','c','d','e' };
	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));

	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));
return 0;
}

题目解释1:

char arr[] = { 'a','b','c','d','e' };  //字符数组,每个元素char类型(1字节),这里给定的字符数组arr并不包含空字符。
	printf("%d\n", sizeof(arr));// 5 数组名arr单独放在sizeof内部,计算整个数组的大小。
	printf("%d\n", sizeof(arr + 0)); // 4/8 数组名arr没有单独放在sizeof内部,且没有&,表示数组首元素的地址,arr+0还是首元素的地址,地址大小为4或8个字节。
	printf("%d\n", sizeof(*arr));// 1 *arr==*(arr+0)==arr[0],对数组首元素的地址解引用表示数组首元素,大小为1字节。
	printf("%d\n", sizeof(arr[1]));// 1 表示数组第二个元素,大小为1个字节。
	printf("%d\n", sizeof(&arr));// 4/8 表示数组的地址,地址大小为4或者8个字节。
	printf("%d\n", sizeof(&arr + 1));// 4/8 表示跳过该数组的地址,是地址就是4或者8个字节。
	printf("%d\n", sizeof(&arr[0] + 1));// 4/8 表示第二个元素的地址,是地址就是4或者8个字节。


	printf("%d\n", strlen(arr));//随机值,strlen函数是通过寻找数组中的空字符('\0')来确定字符串的长度的。然而,给定的字符数组arr并不包含空字符,strlen(arr)可能会继续向后遍历内存直到遇到一个空字符。注意与sizeof(arr)不同的是,这里的arr是首元素地址。
	printf("%d\n", strlen(arr + 0)); // 随机值,arr+0还是首元素地址。
	printf("%d\n", strlen(*arr));// 错误,arr是数组首元素地址,*arr就是数组首元素 'a', strlen认为传参进去的'a'-97就是地址,若97作为地址,直接进行访问,就是非法访问。
	printf("%d\n", strlen(arr[1])); //错误,表示数组第二个元素,与上题错误原因一样。
	printf("%d\n", strlen(&arr)); //随机值 &arr表示数组的地址,char (*)[5]
	printf("%d\n", strlen(&arr + 1));// 随机值 表示该数组下一个的地址
	printf("%d\n", strlen(&arr[0] + 1)); // 随机值 表示数组第二个元素的地址

题目实例2:

#include<stdio.h>
#include<string.h>
int main() {
	char arr[] = "abcde";
	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));

	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));
return 0;
}

题目解释2:

char arr[] = "abcde";  字符串末尾有'\0'
	printf("%d\n", sizeof(arr));  // 6 整个数组的大小
	printf("%d\n", sizeof(arr + 0)); //其余的与题1一致
	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));

	printf("%d\n", strlen(arr)); // 5 首元素地址,从首元素开始往后统计
	printf("%d\n", strlen(arr + 0)); // 5
	printf("%d\n", strlen(*arr)); //错误
	printf("%d\n", strlen(arr[1])); //错误
	printf("%d\n", strlen(&arr)); // 5 数组的地址
	printf("%d\n", strlen(&arr + 1)); // 随机值 表示该数组下一个的地址,从'\0'之后开始,不知道下一次遇到空字符在哪。
	printf("%d\n", strlen(&arr[0] + 1)); //4 表示第二个元素的地址,从该地址往后直到'\0',有4个。
	

在这里插入图片描述

题目实例3:

#include<stdio.h>
#include<string.h>
int main() {
	char* p = "abcde";
	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));

	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));
	return 0;
}

题目解释3:

char* p = "abcde";
	printf("%d\n", sizeof(p)); // 4/8 计算指针变量的大小,为4或者8个字节
	//指针变量的大小和类型无关,不管什么类型的指针变量,大小都是4/8个字节。比如char*,int *,double*大小都一样。
	//指针变量是用来存放地址的,地址存放需要多大空间,指针变量的大小就是几个字节。32位环境下,地址是32个二进制位,需要4个字节,所以指针变量的大小就是4个字节;同理,64位环境下,地址是64个二进制位,需要8个字节,所以指针变量的大小就是8个字节。
	printf("%d\n", sizeof(p + 1)); // 4/8 p+1还是地址
	printf("%d\n", sizeof(*p)); // 1 *p=='a'
	printf("%d\n", sizeof(p[0])); // 1  p[0]==*(p+0)==*p
	printf("%d\n", sizeof(&p)); // 4/8 
	printf("%d\n", sizeof(&p + 1)); // 4/8
	printf("%d\n", sizeof(&p[0] + 1)); // 4/8

地址仅做实例说明

  • 16
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值