[c语言日寄] 指针学习情况自检题目
【作者主页】siy2333
【专栏介绍】⌈c语言日寄⌋:这是一个专注于C语言刷题的专栏,精选题目,搭配详细题解、拓展算法。从基础语法到复杂算法,题目涉及的知识点全面覆盖,助力你系统提升。无论你是初学者,还是进阶开发者,这里都能满足你的需求!
【食用方法】1.根据题目自行尝试 2.查看基础思路完善题解 3.学习拓展算法
【Gitee链接】资源保存在我的Gitee仓库:https://gitee.com/siy2333/study
文章目录
- 前言
- 题目引入
- 知识点分析
- sizeof 运算符
- 指针与数组的关系
- 地址运算
- 答案
- 注意事项
- sizeof 的返回值
- 指针的大小
- 数组与指针的区别
- 地址运算的陷阱
- 拓展应用
- 指针与函数
- 指针与结构体
- 指针与动态内存分配
- 指针与字符串
- 指针与多维数组
- 总结
前言
在 C 语言的世界里,指针是一种强大而灵活的工具,它允许我们直接操作内存地址。今天,我们就通过一个程序练习来复习指针的使用。
题目引入
#include <stdio.h>
int main() {
int a[] = {1, 2, 3, 4}; // 内存大小为4 * 4 = 16字节
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[0]));
printf("%d\n", sizeof(&a[0] + 1));
return 0;
}
请分析程序的输出结果,并解释每条 printf
语句的含义。
在接下来的文章中,我们会一起把指针的知识与题目结合起来,学习这一知识点。
知识点分析
sizeof 运算符
sizeof
是一个编译时运算符
,用于计算变量或数据类型在内存中所占用的字节数。它在处理数组和指针时有一些需要注意的地方。
- 数组:当
sizeof
的操作数是数组名时,它会返回整个数组占用的字节数。例如,sizeof(a)
返回的是数组a
的总大小,即4 * sizeof(int)
。 - 指针:当
sizeof
的操作数是指针时,它返回的是指针本身占用的字节数,而不是指针所指向的内容。在 32 位系统中,指针通常占用 4 字节;在 64 位系统中,指针通常占用 8 字节。
指针与数组的关系
在 C 语言中,数组名在大多数情况下可以被视为指向数组首元素的指针。例如,a
可以被视为 &a[0]
,即数组第一个元素的地址。因此,a + 1
表示数组第二个元素的地址。
sizeof(a + 0)
:a + 0
是数组首元素的地址,sizeof(a + 0)
返回的是指针占用的字节数。sizeof(*a)
:*a
是数组首元素的值,sizeof(*a)
返回的是数组首元素占用的字节数,即sizeof(int)
。sizeof(a + 1)
:a + 1
是数组第二个元素的地址,sizeof(a + 1)
返回的是指针占用的字节数。sizeof(a[1])
:a[1]
是数组第二个元素的值,sizeof(a[1])
返回的是数组第二个元素占用的字节数,即sizeof(int)
。
地址运算
在 C 语言中,地址运算符 &
用于获取变量的地址,而解引用运算符 *
用于获取指针所指向的值。
sizeof(&a)
:&a
是整个数组的地址,sizeof(&a)
返回的是指针占用的字节数。sizeof(*&a)
:&a
是整个数组的地址,*&a
表示整个数组,sizeof(*&a)
返回的是整个数组占用的字节数。sizeof(&a[0])
:&a[0]
是数组第一个元素的地址,sizeof(&a[0])
返回的是指针占用的字节数。sizeof(&a[0] + 1)
:&a[0] + 1
是数组第二个元素的地址,sizeof(&a[0] + 1)
返回的是指针占用的字节数。
答案
#include<stdio.h>
int main() {
int a[] = {1, 2, 3, 4}; // 内存大小为4*4=16字节
printf("%d\n", sizeof(a));
// sizeof()中直接放入数组名,计算整个数组的内存大小:16字节
printf("%d\n", sizeof(a + 0));
// 先计算a+0,代表第一个元素的地址,地址在内存中为4/8个字节
printf("%d\n", sizeof(*a));
//*a为第一个元素,也就是1,int类型占4字节
printf("%d\n", sizeof(a + 1));
// a+1为第二个元素,同上为4字节
printf("%d\n", sizeof(a[1]));
// 第二个元素,4字节
printf("%d\n", sizeof(&a));
// &a为整个元素的地址,地址就占据4/8个字节
printf("%d\n", sizeof(*&a));
// &a表示整个数组的地址,*&a表示整个数组
// 将数组传入得到数组的大小,即4*4=16字节
printf("%d\n", sizeof(&a[0]));
// 第一个元素的地址,地址占4/8字节
printf("%d\n", sizeof(&a[0] + 1));
// 第二个元素的地址,4/8字节
return 0;
}
注意事项
sizeof 的返回值
sizeof
的返回值是 size_t
类型,它是一个无符号整数类型,表示对象的大小。在不同的系统中,size_t
的大小可能不同,但它通常与系统的指针大小一致。因此,在 32 位系统中,size_t
通常占用 4 字节;在 64 位系统中,size_t
通常占用 8 字节。
指针的大小
指针的大小与系统的位数有关。在 32 位系统中,指针占用 4 字节;在 64 位系统中,指针占用 8 字节。因此,sizeof(a + 0)
和 sizeof(&a)
的返回值可能因系统而异。
数组与指针的区别
虽然数组名在大多数情况下可以被视为指针,但数组和指针在某些情况下是有区别的。例如,sizeof(a)
返回的是整个数组的大小,而 sizeof(&a)
返回的是数组的地址占用的字节数。
地址运算的陷阱
在进行地址运算时,需要注意指针的类型和大小。例如,&a[0] + 1
是数组第二个元素的地址,但它的类型是指针,因此 sizeof(&a[0] + 1)
返回的是指针占用的字节数,而不是数组第二个元素的大小。
拓展应用
指针与函数
指针可以作为函数的参数或返回值,这使得函数可以操作内存中的数据。
- 函数参数:当指针作为函数参数时,函数可以通过指针直接修改调用者的变量。例如,我们可以定义一个函数来交换两个整数的值:
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
- 函数返回值:函数也可以返回指针,这使得函数可以返回动态分配的内存或数组的地址。例如,我们可以定义一个函数来创建一个动态分配的数组:
int *create_array(int size) {
int *array = (int *)malloc(size * sizeof(int));
return array;
}
指针与结构体
指针可以与结构体结合使用,这使得我们可以操作结构体的成员。
- 结构体指针:我们可以定义一个指向结构体的指针,并通过指针访问结构体的成员。例如:
struct stu {
int num;
char name[10];
int age;
};
struct stu *p = (struct stu *)malloc(sizeof(struct stu));
p->num = 1001;
strcpy(p->name, "Alice");
p->age = 20;
- 结构体数组指针:我们也可以定义一个指向结构体数组的指针,并通过指针访问结构体数组的元素。例如:
struct stu *p = (struct stu *)malloc(3 * sizeof(struct stu));
p[0].num = 1001;
strcpy(p[0].name, "Alice");
p[0].age = 20;
p[1].num = 1002;
strcpy(p[1].name, "Bob");
p[1].age = 21;
p[2].num = 1003;
strcpy(p[2].name, "Charlie");
p[2].age = 22;
指针与动态内存分配
指针可以用于动态内存分配,这使得我们可以根据需要分配和释放内存。
- malloc:
malloc
函数用于动态分配内存,它返回一个指向分配的内存的指针。例如:
int *array = (int *)malloc(10 * sizeof(int));
- free:
free
函数用于释放动态分配的内存。例如:
free(array);
指针与字符串
指针可以用于处理字符串,这使得我们可以操作字符数组。
- 字符串指针:我们可以定义一个指向字符串的指针,并通过指针操作字符串。例如:
char *str = "Hello, World!";
printf("%s\n", str);
- 字符串数组指针:我们也可以定义一个指向字符串数组的指针,并通过指针操作字符串数组。例如:
char *strs[] = {"Hello", "World", "C", "Language"};
printf("%s\n", strs[0]);
指针与多维数组
指针可以用于处理多维数组,这使得我们可以操作多维数组的元素。
- 二维数组指针:我们可以定义一个指向二维数组的指针,并通过指针操作二维数组的元素。例如:
int array[2][3] = {{1, 2, 3}, {4, 5, 6}};
int (*p)[3] = array;
printf("%d\n", p[0][1]);
- 动态分配二维数组:我们也可以动态分配二维数组,并通过指针操作二维数组的元素。例如:
int **array = (int **)malloc(2 * sizeof(int *));
for (int i = 0; i < 2; i++) {
array[i] = (int *)malloc(3 * sizeof(int));
}
array[0][0] = 1;
array[0][1] = 2;
array[0][2] = 3;
array[1][0] = 4;
array[1][1] = 5;
array[1][2] = 6;
printf("%d\n", array[0][1]);
总结
指针是 C 语言中一个非常重要的概念,它允许我们直接操作内存地址。通过指针,我们可以实现高效的数据操作和复杂的程序功能。在使用指针时,需要注意 sizeof
的返回值、指针的大小、数组与指针的区别以及地址运算的陷阱。此外,指针还可以与函数、结构体、动态内存分配、字符串和多维数组结合使用,实现更强大的功能。希望这篇文章能帮助你更好地理解和使用指针。
关注窝,每三天至少更新一篇优质c语言题目详解~
[专栏链接QwQ] :⌈c语言日寄⌋CSDN
[关注博主ava]:siy2333
感谢观看~ 我们下次再见!!