C语言:复习

ops/2024/10/21 14:21:31/

文章目录

  • 思维导图
  • 数组和指针
  • 库函数的模拟实现
  • 判断大小端

最近知识学的差不多了,因此开始复习,本篇开始的是对于C语言的复习

思维导图

下面就依据下图,进行内容的整理

在这里插入图片描述

在这里插入图片描述

数组和指针

这个模块算是C语言中比较大的一个模块了,具体概念就不多说了,直接用例题

数组

#include <stdio.h>int main()
{//一维数组int a[] = { 1,2,3,4 };printf("%d\n", sizeof(a));    // 16printf("%d\n", sizeof(a + 0)); // 4/8printf("%d\n", sizeof(*a));    // 4printf("%d\n", sizeof(a + 1)); // 4/8printf("%d\n", sizeof(a[1]));  // 4printf("%d\n", sizeof(&a));    // 4/8printf("%d\n", sizeof(*&a));   // 16printf("%d\n", sizeof(&a + 1));// 4/8printf("%d\n", sizeof(&a[0])); // 4/8printf("%d\n", sizeof(&a[0] + 1));// 4/8//字符数组char arr[] = { 'a','b','c','d','e','f', '\0'};printf("%d\n", sizeof(arr));       // 6printf("%d\n", sizeof(arr + 0));   // 4/8printf("%d\n", sizeof(*arr));      // 1printf("%d\n", sizeof(arr[1]));    // 1printf("%d\n", sizeof(&arr));      // 4/8printf("%d\n", sizeof(&arr + 1));  // 4/8printf("%d\n", sizeof(&arr[0] + 1));// 4/8printf("%d\n", strlen(arr));   // 6printf("%d\n", strlen(arr + 0));// 6//printf("%d\n", strlen((const char*) * arr)); // ? //printf("%d\n", strlen((const char*)arr[1])); // ?printf("%d\n", strlen((const char*)&arr)); // 6printf("%d\n", strlen((const char*)(&arr + 1)));  // 未定义printf("%d\n", strlen((const char*)(&arr[0] + 1))); // 5return 0;
}

指针

int main()
{int a[5] = { 1, 2, 3, 4, 5 };int* ptr = (int*)(&a + 1);  // 指向最后一个元素的下一个位置printf("%d,%d", *(a + 1), *(ptr - 1));  // a[1] 和 a[4]return 0;
}
struct Test
{int Num;char* pcName;short sDate;char cha[2];short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
int main()
{printf("%p\n", p + 0x1);printf("%p\n", (unsigned long)p + 0x1);printf("%p\n", (unsigned int*)p + 0x1);return 0;
}

接下来分析 main() 函数中的 printf 表达式:

  1. printf("%p\n", p + 0x1);
    

    在这里,p 是一个指向 struct Test 的指针,对其进行加 0x1 操作意味着指针向前偏移 0x1struct Test 类型的大小,即偏移 20 字节。因此,p + 0x1 的值为 0x100014%p 格式说明符用于打印指针的值,所以这行代码输出 0x100014

  2. printf("%p\n", (unsigned long)p + 0x1);
    

    首先,将指针 p 强制转换为 unsigned long 类型。虽然 p 的原始类型是一个指针,但转换为 unsigned long 后,它被视为一个数值。然后对这个数值加上 0x1,即 0x100000 + 0x1 = 0x100001。接着,将结果作为指针传递给 printf 函数,使用 %p 格式说明符打印。理论上,这行代码的行为是未定义的,因为 0x100001 不是一个有效的指针值。实际运行时可能会导致程序崩溃或其他不可预期的结果。

  3. printf("%p\n", (unsigned int*)p + 0x1);
    

    这里,将指针 p 强制转换为 unsigned int* 类型,即指向无符号整型的指针。由于 struct Test 大小为 20 字节,而通常情况下 unsigned int 类型为 4 字节(具体字节数可能因编译器和平台而异),所以 p 指向的对象大小与 unsigned int* 类型指针所期望的对象大小不匹配。接着,对转换后的指针加上 0x1,即偏移 4 字节。最后,将结果作为指针传递给 printf 函数,使用 %p 格式说明符打印。这行代码同样存在未定义行为,因为指针类型转换后与原始对象大小不匹配,后续操作可能导致程序崩溃或其他不可预期的结果。

综上所述:

  • 第一个 printf 表达式输出 0x100014,这是正确地对 struct Test 类型指针进行偏移后的结果。
  • 第二个和第三个 printf 表达式涉及不恰当的指针类型转换和指针运算,其行为是未定义的,可能会导致程序崩溃或其他不可预期的结果。在实际编程中应避免这类操作。
int main()
{int a[4] = { 1, 2, 3, 4 };// 1000 0000 0000 0000 0000 0000 0000 0000 // 0100 0000 0000 0000 0000 0000 0000 0000// 00        00        00        02// 0000 0000 0000 0000 0000 0000 0000 0100int* ptr1 = (int*)(&a + 1); // 最后一个元素的下一个位置int* ptr2 = (int*)((int)a + 1);printf("%x,%x", ptr1[-1], *ptr2); // 最后一个元素return 0;
}
#include <stdio.h>int main()
{int a[3][2] = { (0, 1), (2, 3), (4, 5) };int* p;p = a[0];printf("%d", p[0]); // p + 0 实际存储的是1 3 5 0 0 ...return 0;
}
#include <stdio.h>
int main()
{// 1, 2, 3, 4, 5// 6, 7, 8, 9, 10int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };int* ptr1 = (int*)(&aa + 1); // 跳过了整个二维数组int* ptr2 = (int*)(*(aa + 1)); // aa[1]printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1)); // 10 5return 0;
}
#include <stdio.h>
int main()
{const char* a[] = { "work","at","alibaba" };const char** pa = a; // wpa++; // atprintf("%s\n", *pa);return 0;
}

库函数的模拟实现

void* mymemcpy(void* destination, const void* source, size_t num)
{void* res = destination;assert(destination);assert(source);while (num--){*(char*)destination = *(char*)source;destination = (char*)destination + 1;source = (char*)source + 1;}return res;
}
void* mymemmove(void* destination, const void* source, size_t num)
{void* res = destination;assert(destination);assert(source);if (destination <= source || (char*)destination >= ((char*)source) + num){destination = (char*)destination + num - 1;source = (char*)source + num - 1;while (num--){*(char*)destination = *(char*)source;destination = (char*)destination - 1;source = (char*)source - 1;}}else{while (num--){*(char*)destination = *(char*)source;destination = (char*)destination + 1;source = (char*)source + 1;}}return res;
}

判断大小端

union MyUnion
{int a;char c[4];
};
int main()
{MyUnion un;un.a = 0x123456;if (un.c[0] == 0x12)printf("大端\n");elseprintf("小端\n");return 0;
}int main()
{int a = 0x123456;char* pa = (char*)&a;if (*pa == 0x12)printf("大端\n");elseprintf("小端\n");return 0;
}

http://www.ppmy.cn/ops/15879.html

相关文章

C++:继承

继承定义 继承是面向对象编程中的一个重要概念。它的由来可以追溯到软件开发中的模块化设计和代码复用的需求。 在软件开发过程中&#xff0c;我们经常会遇到需要为多个类添加相同的行为或属性的场景&#xff0c;这样就产生了代码重复的问题。为了解决这个问题&#xff0c;工…

【静态分析】静态分析笔记07 - 指针分析基础

参考&#xff1a; 【课程笔记】南大软件分析课程7——指针分析基础&#xff08;课时9/10&#xff09; - 简书 -------------------------------------------------------------- 1. 指针分析规则 规则&#xff1a;采用推导形式&#xff0c;横线上面是条件&#xff0c;横线下…

Spring Boot 目前还是最先进的吗?

当谈到现代Java开发框架时&#xff0c;Spring Boot一直处于领先地位。它目前不仅是最先进的&#xff0c;而且在Java生态系统中拥有着巨大的影响力。 1. 什么是Spring Boot&#xff1f; Spring Boot是由Spring团队开发的开源框架&#xff0c;旨在简化基于Spring的应用程序的开…

【面试题】java后端开发实习(含答案)

java后端开发实习生-常见面试题 1&#xff09;JDK,JRE,JVM的关系 JDK JRE java开发工具JRE JVM java核心类库 2&#xff09;String类的常用方法 1.关于字符串获取方面 length 获取长度charAt 获取指定索引的字符indexOf 获取字符所在的索引位置lastIndexOf 获取字符所在…

XiaodiSec day014 Learn Note 小迪安全学习笔记

XiaodiSec day014 Learn Note 小迪安全学习笔记 记录得比较凌乱&#xff0c;不尽详细 day 14 输入输出类内容 php全局变量 server mysql插入语法insert 搜索文件&#xff0c;提交表单 使用Php连接数据库&#xff0c;使用sql语句中的like 进行模糊查询 使用php查询内容&am…

restful请求风格的增删改查-----查询and添加

一、restful风格的介绍 restful也称之为REST ( Representational State Transfer )&#xff0c;可以将它理解为一种软件架构风格或设计风格&#xff0c;而不是一个标准。简单来说&#xff0c;restful风格就是把请求参数变成请求路径的一种风格。例如&#xff0c;传统的URL请求…

dns高防和ip高防的区别是什么?

在面对日益增长的网络安全威胁时&#xff0c;DNS高防和IP高防作为防御策略发挥着重要的作用。虽然两者都旨在保护网络资源免受攻击&#xff0c;但它们在操作方式和防护重点上有着本质的不同。 DNS高防&#xff1a;保护域名解析服务DNS高防&#xff0c;全称是高防御的域名解析服…

SAP SD 常用表

SO&#xff1a; 表ID表名VBAK销售凭证 &#xff1a; 抬头数据VBUK销售凭证&#xff1a;抬头状态和管理数据VAPMA销售索引 &#xff1a; 按物料的订单项目VAKPA销售索引 &#xff1a; 按合作伙伴功能的订单VKDFSSD索引&#xff1a; 出具发票初始器KONV条件&#xff08;事务数据…