c语言练习题(指针内容)

习题1

cs 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main() {
	int a[] = { 1,2,3,4 };
	printf("%d\n", sizeof(a));//16
	//sizeof(数组名),数组名表示整个数组,计算的是整个数组的大小,单位是字节

	printf("%d\n", sizeof(a + 0));//4
	//a不是单独放在sizeof内部,也没有取地址,所以a就是首元素的地址,a+0还是首元素的地址
	//是地址大小就是4个字节

	printf("%d\n",sizeof(*a));//4
	//*a中的a是数组首元素的地址,*a就是对首元素的地址的解引用,找到的就是首元素
	//首元素的大小就是4个字节

	printf("%d\n", sizeof(a + 1));//4
	这里的a是数组首元素的地址
    //a+1是第二个元素的地址

	printf("%d\n", sizeof(a[1]));//4
	//计算的是第二个元素的大小

	printf("%d\n", sizeof(&a));//4或者8
	//&a取出的数组的地址,数组的地址,也就是个地址

	printf("%d\n", sizeof(*&a));// 16
	//&a---->int (*)[4]
	//&a拿到的是数组名的地址,类型是int(*)[4], 是一种数组指针
	//数组指针解引用找到的是数组  *&a---->a

	printf("%d\n", sizeof(&a + 1));//  4或者8
	//&a取出的是数组的地址
	// &a-->int(*)4
	//&a+1是从数组a的地址向后跳过了一个(4个整型元素的)数组的大小
    //a+1还是地址,是地址就是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个字节]
	return 0;
}

总结

  • 对于数组名 a,当它单独放在 sizeof 内部时,表示整个数组。
  • 对于数组名 a,当它与 + 运算符结合使用时,表示数组首元素的地址。
  • 对于地址操作(如 &aa + 0&a[0]),地址的大小在 32 位系统上是 4 字节,在 64 位系统上是 8 字节。
  • 对于解引用操作(如 *a*&a),得到的是数组元素或数组本身,大小取决于数据类型。

习题2

cs 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>

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

    // sizeof(arr) 计算整个数组的大小,单位是字节
    // 数组中有6个字符,每个字符占1个字节,所以结果是6
    printf("%d\n", sizeof(arr)); // 输出: 6

    // arr + 0 表示数组首元素的地址
    // sizeof(arr + 0) 计算的是地址的大小,在32位系统上是4字节,在64位系统上是8字节
    printf("%d\n", sizeof(arr + 0)); // 输出: 4 或 8

    // *arr 表示数组的首元素 'a'
    // sizeof(*arr) 计算的是字符的大小,即1字节
    printf("%d\n", sizeof(*arr)); // 输出: 1

    // arr[1] 表示数组的第二个元素 'b'
    // sizeof(arr[1]) 计算的是字符的大小,即1字节
    printf("%d\n", sizeof(arr[1])); // 输出: 1

    // &arr 表示整个数组的地址
    // sizeof(&arr) 计算的是地址的大小,在32位系统上是4字节,在64位系统上是8字节
    printf("%d\n", sizeof(&arr)); // 输出: 4 或 8

    // &arr + 1 表示从数组地址向后跳过一个数组大小的地址
    // sizeof(&arr + 1) 计算的是地址的大小,在32位系统上是4字节,在64位系统上是8字节
    printf("%d\n", sizeof(&arr + 1)); // 输出: 4 或 8

    // &arr[0] 表示数组第一个元素的地址
    // &arr[0] + 1 表示数组第二个元素的地址
    // sizeof(&arr[0] + 1) 计算的是地址的大小,在32位系统上是4字节,在64位系统上是8字节
    printf("%d\n", sizeof(&arr[0] + 1)); // 输出: 4 或 8

    return 0;
}

习题3

cs 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

int main() {
    char arr[] = "abcdef"; // 定义一个包含字符串 "abcdef" 的字符数组
    // 在 C 语言中,字符串常量自动添加一个结束符 '\0',所以 arr 实际上是 7 个字符:'a', 'b', 'c', 'd', 'e', 'f', '\0'

    // sizeof(arr) 计算整个数组的大小
    // 数组中有 7 个字符(包括结束符 '\0'),每个字符占 1 个字节,所以结果是 7
    printf("%d\n", sizeof(arr)); // 输出: 7 

    // arr + 0 表示数组首元素的地址
    // sizeof(arr + 0) 计算的是这个地址的大小
    // 在 32 位系统上是 4 字节,在 64 位系统上是 8 字节
    printf("%d\n", sizeof(arr + 0)); // 输出: 4 或 8

    // *arr 表示数组的首元素 'a'
    // sizeof(*arr) 计算的是字符的大小,即 1 字节
    printf("%d\n", sizeof(*arr)); // 输出: 1

    // arr[1] 表示数组的第二个元素 'b'
    // sizeof(arr[1]) 计算的是字符的大小,即 1 字节
    printf("%d\n", sizeof(arr[1])); // 输出: 1

    // &arr 表示整个数组的地址
    // sizeof(&arr) 计算的是地址的大小,在 32 位系统上是 4 字节,在 64 位系统上是 8 字节
    printf("%d\n", sizeof(&arr)); // 输出: 4 或 8

    // &arr + 1 表示从数组地址向后跳过一个数组的大小
    // sizeof(&arr + 1) 计算的是地址的大小,在 32 位系统上是 4 字节,在 64 位系统上是 8 字节
    printf("%d\n", sizeof(&arr + 1)); // 输出: 4 或 8

    // &arr[0] 表示数组第一个元素的地址
    // &arr[0] + 1 表示数组第二个元素的地址
    // sizeof(&arr[0] + 1) 计算的是地址的大小,在 32 位系统上是 4 字节,在 64 位系统上是 8 字节
    printf("%d\n", sizeof(&arr[0] + 1)); // 输出: 4 或 8

    return 0;
}

习题4

cs 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h> // 需要包含 string.h 头文件以使用 strlen 函数

//strlen是求字符串长度的,关注的是字符串中的8,计算的是\之前出现的字符的个数
//strlen是库函数,只针对字符串
//sizeof只关注占用内存空间的大小,不在乎内存中放的是什么
//sizeof是操作符

int main() {
    char arr[] = "abcdef"; 
    // 定义一个包含字符串 "abcdef" 的字符数组
    // 在 C 语言中,字符串常量自动添加一个结束符 '\0',
    //所以 arr 实际上是 7 个字符:'a', 'b', 'c', 'd', 'e', 'f', '\0'

    // strlen(arr) 计算字符串的长度,不包括结束符 '\0'
    // 字符串 "abcdef" 有 6 个字符,所以结果是 6
    printf("%d\n", strlen(arr)); // 输出: 6

    // arr + 0 表示数组首元素的地址,即字符串的起始地址
    // strlen(arr + 0) 计算字符串的长度,结果是 6
    printf("%d\n", strlen(arr + 0)); // 输出: 6




    // *arr 表示数组的首元素 'a',字符 'a' 的 ASCII 码值是 97
    // strlen(*arr) 试图计算以 97 为地址的字符串长度,这会导致未定义行为(非法访问内存)
    // 一般情况下,程序会崩溃或产生不可预期的结果
    // printf("%d\n", strlen(*arr)); // 未定义行为,程序可能会崩溃



    // arr[1] 表示数组的第二个元素 'b',字符 'b' 的 ASCII 码值是 98
    // strlen(arr[1]) 试图计算以 98 为地址的字符串长度,这会导致未定义行为(非法访问内存)
    // 一般情况下,程序会崩溃或产生不可预期的结果
    // printf("%d\n", strlen(arr[1])); // 未定义行为,程序可能会崩溃





    // &arr 表示整个数组的地址,但它仍然是字符串的起始地址
    // strlen(&arr) 计算字符串的长度,结果是 6
    printf("%d\n", strlen(&arr)); // 输出: 6

    // &arr + 1 表示从数组地址向后跳过一个数组的大小,指向数组结束后的位置
    // strlen(&arr + 1) 计算从这个位置开始的字符串长度,这会导致未定义行为(非法访问内存)
    // 一般情况下,程序会崩溃或产生不可预期的结果
    // printf("%d\n", strlen(&arr + 1)); // 未定义行为,程序可能会崩溃

    // &arr[0] 表示数组第一个元素的地址,&arr[0] + 1 表示数组第二个元素的地址
    // strlen(&arr[0] + 1) 计算从第二个元素开始的字符串长度,结果是 5
    printf("%d\n", strlen(&arr[0] + 1)); // 输出: 5

    return 0;
}

习题5

cs 复制代码
#include <stdio.h>
#include <string.h> // 需要包含 string.h 头文件以使用 strlen 函数

int main() {
    char* p = "abcdef"; // 定义一个指向字符串常量 "abcdef" 的指针

    // sizeof(p) 计算指针 p 的大小
    // 在 32 位系统下是 4 字节,在 64 位系统下是 8 字节
    printf("%d\n", sizeof(p)); // 输出: 4 或 8


    // sizeof(p + 1) 计算的是指针的大小(p + 1 依然是指针)
    printf("%d\n", sizeof(p + 1)); // 输出: 4 或 8


    // sizeof(*p) 计算的是 char 类型的大小,即 1 字节
    printf("%d\n", sizeof(*p)); // 输出: 1


    // sizeof(p[0]) 也是计算第一元素 'a' 的大小,结果也是 1 字节
    printf("%d\n", sizeof(p[0])); // 输出: 1


    // sizeof(&p) 计算的是指针 p 的地址(指向 char* 的指针),大小在 32 位系统下是 4 字节,在 64 位系统下是 8 字节
    printf("%d\n", sizeof(&p)); // 输出: 4 或 8


    // sizeof(&p + 1) 计算的是第二级指针的大小(sizeof(char**)),结果指针的大小,4 或 8 字节
    printf("%d\n", sizeof(&p + 1)); // 输出: 4 或 8


    // sizeof(&p[0] + 1) 计算的是偏移后的指针大小,指向下一个字符,输出 result 是 4 或 8。
    printf("%d\n", sizeof(&p[0] + 1)); // 输出: 4 或 8


    // strlen(p) 计算字符串的长度,不包括结束符 '\0',结果是 6
    printf("%d\n", strlen(p)); // 输出: 6


    // strlen(p + 1) 计算从 'b' 开始到末尾的长度,即 "bcdef",结果是 5
    printf("%d\n", strlen(p + 1)); // 输出: 5


    // strlen(*p) 将会导致未定义行为,因为 *p 是字符 'a',将其作为指针处理是不正确的
    // printf("%d\n", strlen(*p)); // 可能导致崩溃或未定义行为


    // strlen(p[0]) 同样是不正确的,p[0] 是 'a',作为参数传入也是不正确
    // printf("%d\n", strlen(p[0])); // 可能导致崩溃或未定义行为


    // strlen(&p) 计算的是 p 的地址,以指针形式传入,结果是不正确的(不代表字符串)。
    // printf("%d\n", strlen(&p)); //随机值


    // strlen(&p + 1) 计算的是结束后的位置,结果也是未定义的。
    // printf("%d\n", strlen(&p + 1)); //随机值


    // strlen(&p[0] + 1) 计算的是从 'b' 开始的字符串长度,结果是 5
    printf("%d\n", strlen(&p[0] + 1)); // 输出: 5

    return 0;
}

习题6

cs 复制代码
#include <stdio.h>

int main() {
    int a[3][4] = { 0 }; // 定义一个 3 行 4 列的二维数组

    // sizeof(a) 计算整个二维数组的大小,即 3 行 4 列的 int 数组
    // 每个 int 占 4 字节,总大小为 3 * 4 * 4 = 48 字节
    printf("%d\n", sizeof(a)); // 输出: 48

    // sizeof(a[0][0]) 计算二维数组第一个元素的大小,即一个 int 的大小
    printf("%d\n", sizeof(a[0][0])); // 输出: 4

    // sizeof(a[0]) 计算第一行的数组大小,即 4 个 int 的大小
    // 总大小为 4 * 4 = 16 字节
    printf("%d\n", sizeof(a[0])); // 输出: 16

    // a[0] 是第一行的数组名,a[0] + 1 是数组首元素的地址加 1,即指向 a[0][1]
    // sizeof(a[0] + 1) 计算的是指针的大小,在 32 位系统下是 4 字节,在 64 位系统下是 8 字节
    printf("%d\n", sizeof(a[0] + 1)); // 输出: 4 或 8

    // (*a[0] + 1) 是未定义行为,a[0] 是一个数组名,不是指针
    // printf("%d\n", sizeof((*a[0] + 1))); // 未定义行为

    // a 是二维数组的数组名,a + 1 指向第二行的起始地址
    // sizeof(a + 1) 计算的是指针的大小,在 32 位系统下是 4 字节,在 64 位系统下是 8 字节
    printf("%d\n", sizeof(a + 1)); // 输出: 4 或 8

    // *(a + 1) 是第二行的数组名,等价于 a[1]
    // sizeof(*(a + 1)) 计算第二行的数组大小,即 4 个 int 的大小,总大小为 4 * 4 = 16 字节
    printf("%d\n", sizeof(*(a + 1))); // 输出: 16

    // &a[0] 是第一行的地址,&a[0] + 1 指向第二行的起始地址
    // sizeof(&a[0] + 1) 计算的是指针的大小,在 32 位系统下是 4 字节,在 64 位系统下是 8 字节
    printf("%d\n", sizeof(&a[0] + 1)); // 输出: 4 或 8

    // *(&a[0] + 1) 是第二行的数组名,等价于 a[1]
    // sizeof(*(&a[0] + 1)) 计算第二行的数组大小,总大小为 4 * 4 = 16 字节
    printf("%d\n", sizeof(*(&a[0] + 1))); // 输出: 16

    // *a 是第一行的数组名,等价于 a[0]
    // sizeof(*a) 计算第一行的数组大小,总大小为 4 * 4 = 16 字节
    printf("%d\n", sizeof(*a)); // 输出: 16

    // a[3] 越界访问,但 sizeof 是在编译时计算的,所以不会导致运行时错误
    // 编译器会认为 a[3] 是一个数组名,计算 4 个 int 的大小,总大小为 4 * 4 = 16 字节
    printf("%d\n", sizeof(a[3])); // 输出: 16

    return 0;
}

习题7

cs 复制代码
#include <stdio.h>

int main() {
    int a[5] = { 1, 2, 3, 4, 5 };
    int* ptr = (int*)(&a + 1); // &a 是整个数组的指针,&a + 1 指向数组末尾后的位置

    // *(a + 1) 访问的是数组 a 的第二个元素,即 a[1]
    // *(ptr + 1) 访问的是数组 a 末尾后的内存位置,这是未定义行为
    printf("%d, %d\n", *(a + 1), *(ptr - 1)); //2 5
   // 这里我们改为 *(ptr - 1) 来访问数组 a 的最后一个元素

    return 0;
}
  1. &a 是整个数组 a 的指针,类型是 int (*)[5],即指向包含 5 个 int 的数组的指针。
  2. &a + 1 指向数组 a 末尾后的位置,即指向下一个 int[5] 数组的位置。
  3. (int*)(&a + 1)&a + 1 强制转换为 int* 类型,指向数组 a 末尾后的位置。
  4. *(a + 1) 访问的是数组 a 的第二个元素,即 a[1],值为 2
  5. *(ptr - 1) 访问的是数组 a 的最后一个元素,即 a[4],值为 5

习题8

cs 复制代码
#include <stdio.h>

// 定义结构体 test
struct test {
    int num;         // 4 字节
    char* name;      // 指针,通常为 4 或 8 字节(32位系统为4字节,64位系统为8字节)
    short date;      // 2 字节
    char cha[2];     // 2 字节
    short sba[4];    // 8 字节(4 个 short,每个 2 字节)
} *p;

  //假设p的值为0x100000.如下表达式的值分别为多少
  //已知结构体test类型的变量大小是20个字节

int main() {
    p = (struct test*)0x100000; // 假设 p 的值为 0x100000

    // (1) p + 0x1
    // p 是一个指向 test 结构体的指针,p + 0x1 表示 p 向前移动 1 个 test 结构体的大小
    // 结构体 test 的大小是 20 字节,所以结果是将指针 p 增加 20 字节,即 0x100014
    printf("%p\n", p + 0x1);        // 输出: 0x100014



    // (2) (unsigned long)p + 0x1
    // p 被强制转换为 unsigned long 类型,这时它不再是一个指针,而是一个整数
    // 因此,(unsigned long)p + 0x1 只是将 p 的整数值 0x100000 加上 0x1,结果是 0x100001
    printf("%p\n", (unsigned long)p + 0x1); // 输出: 0x100001



    // (3) (unsigned int*)p + 0x1
    // p 被强制转换为 unsigned int* 类型,这时它是一个指向 unsigned int 的指针
    // p + 0x1 表示 p 向前移动 1 个 unsigned int 的大小
    // 在 x86 架构下,unsigned int 的大小是 4 字节,所以结果是将指针 p 增加 4 字节,即 0x100004
    printf("%p\n", (unsigned int*)p + 0x1); // 输出: 0x100004

    return 0;
}

习题8

cs 复制代码
#include <stdio.h>

int main() {
    // 定义一个二维数组 a,大小为 3x2,并初始化
    // 注意:这里使用了逗号表达式 (0,1), (2,3), (4,5)
    // 逗号表达式的值是最后一个表达式的值,因此:
    // (0,1) 的结果是 1
    // (2,3) 的结果是 3
    // (4,5) 的结果是 5
    // 所以数组 a 实际上被初始化为:
    // a[0][0] = 1, a[0][1] = 3
    // a[1][0] = 5, a[1][1] = 0(未初始化,默认为 0)
    // a[2][0] = 0, a[2][1] = 0(未初始化,默认为 0)



    int a[3][2] = { (0,1),(2,3),(4,5) };
    
    // 定义一个指向 int 的指针 p
    int* p;
    
    // 将 p 指向数组 a 的第一个元素 a[0],即 p 指向 a[0][0]
    p = a[0];
    
    // 输出 p[0],即 a[0][0],其值为 1
    printf("%d", p[0]);
    
    return 0;
}
相关推荐
Algorithm15766 分钟前
JVM是什么,与Java的关系是什么,以及JVM怎么实现的跨平台性
java·开发语言·jvm
Gnevergiveup7 分钟前
2024网鼎杯青龙组Web+Misc部分WP
开发语言·前端·python
DdddJMs__13513 分钟前
C语言 | Leetcode C语言题解之第517题超级洗衣机
c语言·leetcode·题解
边疆.21 分钟前
C++类和对象 (中)
c语言·开发语言·c++·算法
yy_xzz23 分钟前
QT编译报错:-1: error: cannot find -lGL
开发语言·qt
你不讲 wood26 分钟前
使用 Axios 上传大文件分片上传
开发语言·前端·javascript·node.js·html·html5
binqian34 分钟前
【K8S】kubernetes-dashboard.yaml
算法·贪心算法
林浔090634 分钟前
C语言部分输入输出(printf函数与scanf函数,getchar与putchar详解,使用Linux ubuntu)
c语言·开发语言
Wils0nEdwards1 小时前
Leetcode 合并 K 个升序链表
算法·leetcode·链表
一颗甜苞谷1 小时前
开源一款基于 JAVA 的仓库管理系统,支持三方物流和厂内物流,包含 PDA 和 WEB 端的源码
java·开发语言·开源