C语言部分复习笔记

1. 指针和数组

数组指针 和 指针数组

 int* p1[10]; // 指针数组int (*p2)[10]; // 数组指针

因为 [] 的优先级比 * 高,p先和 [] 结合说明p是一个数组,p先和*结合说明p是一个指针

括号保证p先和*结合,说明p是一个指针变量,然后指着指向的是一个大小为10个整型的数组。所以p是一个 指针,指向一个数组,叫数组指针。

arr和&arr的区别

arr代表数组首元素的地址,&arr代表整个数组的地址

 void test(int(*arr)[10], int size) // 这里arr也是整个数组的数组指针{for (int i = 0; i < size; ++i){cout << ((int*)arr)[i] << " ";}cout << endl;}​int main(){int arr[10] = { 0 };int(*p)[10] = &arr; // 数组指针需要指整个数组test(p, 10);return 0;}

二维数组传参

 
void test(int arr[3][5])//ok?{}void test(int arr[][])//ok? X{}void test(int arr[][5])//ok?{}// 总结:二维数组传参,函数形参的设计只能省略第一个[]的数字。// 因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。这样才方便运算。void test(int* arr)//ok?X{}void test(int* arr[5])//ok?{}void test(int(*arr)[5])//ok?arr是指向一个大小为5的一维数组{}void test(int** arr)//ok?{}int main(){int arr[3][5] = { 0 };test(arr);}

函数指针

保存函数的地址:函数指针

 #include <stdio.h>void test(){}​int main(){printf("%p\n", test);printf("%p\n", &test); // 一样cout << typeid(test).name() << endl; // void __cdecl(void) 函数名cout << typeid(&test).name() << endl; // void (__cdecl*)(void) 函数指针void(*p1)(void) = test;void(*p2)(void) = &test; // 一样的return 0;}

函数指针数组

 typedef void(*handler)(void);​int main(){handler arr[12] = { 0 };void(*arr1[12])(void)  = { 0 };}

const和指针

const修饰的指针变量:

  1. const位于*前的,表示指针指向的对象内容无法修改,p指向的空间内容(指向对象的内容)无法修改

  2. const位于*后面的,表示指针指向的位置无法修改,p的内容(保存的对象地址)无法修改

     const int* p = nullptr;int const* p = nullptr;int* const p = nullptr;

sizeof和指针,数组/strlen和指针,数组

sizeof是根据对象的类型判断大小,但是有一个特殊处理就是数组名,sizeof(数组名)

  1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小

  2. &数组名,这里的数组名表示整个数组,取出的是整个数组的地址

  3. 除此之外所有的数组名都表示首元素的地址

  4. 但是参数数组也是一个特殊的存在,当数组作为参数进行传递的时候,数组其实退化成了指针

 //一维数组int a[] = {1,2,3,4};printf("%d\n",sizeof(a));       // 16printf("%d\n",sizeof(a+0));     // 4/8printf("%d\n",sizeof(*a));      // 4 printf("%d\n",sizeof(a+1));     // 4/8printf("%d\n",sizeof(a[1]));    // 4printf("%d\n",sizeof(&a));      // 4/8printf("%d\n",sizeof(*&a));     // 16(*和&抵消了)printf("%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'}; // 6个 系统不会给最后补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));        // 未知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));     // 报错,因为&arr的类型char(*)[6]printf("%d\n", strlen(&arr[0]+1));  // 未知 优先级 [] > * > &char arr[] = "abcdef";  // 7个 最后补0printf("%d\n", sizeof(arr));        // 7printf("%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));      // 6printf("%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));  // 5const char *p = "abcdef"; // 最后会补'\0'printf("%d\n", sizeof(p));          // 4/8printf("%d\n", sizeof(p+1));        // 4/8printf("%d\n", sizeof(*p));         // 1printf("%d\n", sizeof(p[0]));       // 1printf("%d\n", sizeof(&p));         // 4/8printf("%d\n", sizeof(&p+1));       // 4/8printf("%d\n", sizeof(&p[0]+1));    // 4/8printf("%d\n", strlen(p));          // 6printf("%d\n", strlen(p+1));        // 5printf("%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));    // 5​//二维数组int a[3][4] = {0};printf("%d\n",sizeof(a));           // 48printf("%d\n",sizeof(a[0][0]));     // 4printf("%d\n",sizeof(a[0]));        // 16printf("%d\n",sizeof(a[0]+1));      // 4/8 (指针) a[0][1]// 这里a[0] 表示a的首个元素,因为sizeof的特殊所以被当成整个数组大小 +1 后这个特殊就没了printf("%d\n",sizeof(*(a[0]+1)));   // 4printf("%d\n",sizeof(a+1));         // 4/8printf("%d\n",sizeof(*(a+1)));      // 4/8X  16 a[1]printf("%d\n",sizeof(&a[0]+1));     // 4/8 printf("%d\n",sizeof(*(&a[0]+1)));  // 4X  16   a[1]printf("%d\n",sizeof(*a));          // 4/8X  16 a[0]printf("%d\n",sizeof(a[3]));        // 4/8X  16

总结:先看类型再判断

2. 库函数的模拟实现

memcpy

 void* memcpy(void* dest, const void* src, size_t num){assert(dest && src);char* d = (char*)dest;const char* s = (const char*)src;while (num--){*d++ = *s++;}return dest;}

注意:c++使用括号强转类型,生成的是临时变量,不能进行++

memmove

 void* memmove(void* dest, const void* src, size_t num){assert(dest && src);char* d = static_cast<char*>(dest);const char* s = static_cast<const char*>(src);while (num--){if (dest < src){*d++ = *s++;}else{*((char*)(d + num)) = *(s + num); // 这里根据num的减少来推进}}return dest;}

strstr

 // 从目的字符串中找src字符串static char* strstr(const char* dest, const char* src){assert(dest && src);const char* left = dest, * right = dest;const char* cur = src;while (true){while (*left != '\0' && *left != *cur) left++;if (*left == '\0')break;// *left == *curright = left;while (*right == *cur){right++;cur++;if (*cur == '\0')return const_cast<char*>(left);}cur = src; // cur 回执left++;}return nullptr;}

memset/strcmp

 void* memset(void* ptr, int val, size_t num){assert(ptr);char* cur = static_cast<char*>(ptr);while (num--){*cur++ = val;}return ptr;}int strcmp(const char* str1, const char* str2){assert(str1 && str2);while (*str1 != '\0' && *str2 != '\0' && *str1++ == *str2++);//if (*str1 < *str2)//  return -1;//else if (*str1 > *str2)//  return 1;//else return 0;return *str1 - *str2;}

3. 自定义类型

内存对齐规则

  1. 第一个成员在与结构体变量偏移量为0的地址处。

  2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处

  3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍

  4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍

对齐数 = 编译器默认的一个对齐数(VS下是8) 与 该成员大小的较小值

联合体

联合也是一种特殊的自定义类型 这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间(所以联合也叫共用体)

联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为 联合至少得有能力保存最大的那个成员)

联合大小的计算:

联合的大小至少是最大成员的大小,当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍

4. 整形的存储规则

原码/反码/补码

计算机中的有符号数有三种表示方法,即原码、反码和补码

三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位三种表示方法各不相同

  • 原码:直接将二进制按照正负数的形式翻译成二进制就可以

  • 反码: 将原码的符号位不变,其他位依次按位取反就可以得到了

  • 补码: 反码+1就得到补码

正数的原、反、补码都相同

对于整形来说:数据存放内存中其实存放的是补码

大小端

大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中(高低)

小端(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位,保存在内存的高地址中(高高)

如何判断:

 #include <stdio.h>int check_sys(){int i = 1;return (*(char *)&i);}int main(){int ret = check_sys();if(ret == 1)printf("小端\n");elserintf("大端\n");return 0;}//代码2int check_sys(){union{int i;char c;}un;un.i = 1;return un.c;}

5. 编译链接

#define 替换规则 在程序中扩展#define定义符号和宏时,需要涉及几个步骤:

  1. 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先被替换。

  2. 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值替换。

  3. 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。

注意:

  1. 宏参数和#define 定义中可以出现其他#define定义的变量。但是对于宏,不能出现递归

  2. 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索

也就是说"宏"只会被当成字符串,宏不会生效,这时#宏:把一个宏参数变成对应的字符串

 #include <stdio.h>​#define PRINT1(FORMAT, VALUE) \printf("the value is "FORMAT"\n", VALUE)​#define PRINT2(FORMAT, VALUE) \printf("the value of "#VALUE" is "FORMAT"\n", VALUE) // yes//printf("the value of ""VALUE"" is "FORMAT"\n", VALUE) // no​int main(){char a = -1;signed char b = -1;unsigned char c = -1;printf("a=%d,b=%d,c=%d\n", a, b, c); // 对齐 -1 -1 255printf("file:%s\n line:%d\n time:%s\n", __FILE__, __LINE__, __TIME__);const char* p = "hello ""bit\n"; // 字符串合并printf("%s\n", p);PRINT1("%d", 10);PRINT2("%d", 10);return 0;}

可以把位于它两边的符号合成一个符号。 它允许宏定义从分离的文本片段创建标识符

 #define OFFSETOF(struct_name, member_name) \((size_t)&(((struct_name*)0)->member_name))// 获取成员变量的偏移量

宏的优缺点:

优点

  1. 用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多。所以宏比函数在程序 的规模和速度方面更胜一筹。

  2. 更为重要的是函数的参数必须声明为特定的类型。所以函数只能在类型合适的表达式上使用。反之这个宏怎可 以适用于整形、长整型、浮点型等可以用于>来比较的类型。宏是类型无关的。(C++模板)

缺点

  1. 每次使用宏的时候,一份宏定义的代码将插入到程序中。除非宏比较短,否则可能大幅度增加程序的长度

  2. 宏是没法调试的。

  3. 宏由于类型无关,也就不够严谨

  4. 宏可能会带来运算符优先级的问题,导致程序容易出现错

#undef 于移除一个宏定义

 gcc -D ARRAY_SIZE=10 programe.c // 命令行宏定义

条件编译

 #if defined(OS_UNIX) #ifdef OPTION1 unix_version_option1(); #elif defined(OPTION2)unix_version_option2(); #elseunix_version_option3(); #endif #elif defined(OS_MSDOS) #ifdef OPTION2 msdos_version_option2(); #endif #endif

编译链接过程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/366051.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

R语言 | 使用ggplot绘制柱状图,在柱子中显示数值和显著性

原文链接&#xff1a;使用ggplot绘制柱状图&#xff0c;在柱子中显示数值和显著性 本期教程 获得本期教程示例数据&#xff0c;后台回复关键词&#xff1a;20240628。&#xff08;PS&#xff1a;在社群中&#xff0c;可获得往期和未来教程所有数据和代码&#xff09; 往期教程…

Windows宝塔面板部署ThinkPHP8.0创建Vue项目案例

安装ThinkPHP8.0 登录宝塔面板&#xff0c;创建一个站点。 输入composer代码&#xff0c;执行完成后自动创建TP目录 composer create-project topthink/think tp 网站目录设置为tp&#xff0c;运行目录设置为public 设置PHP版本为8.0以上&#xff0c;不然会出现下面的报错代…

1-5题查询 - 高频 SQL 50 题基础版

目录 1. 相关知识点2. 例题2.1.可回收且低脂的产品2.2.寻找用户推荐人2.3.大的国家2.4. 文章浏览 I2.5. 无效的推文 1. 相关知识点 sql判断&#xff0c;不包含null&#xff0c;判断不出来distinct是通过查询的结果来去除重复记录ASC升序计算字符长度 CHAR_LENGTH() 或 LENGTH(…

js实现blockly后台解释器,可以单步执行,可以调用c/c++函数

实现原理 解析blockly语法树&#xff0c;使用js管理状态&#xff0c;实际使用lua执行&#xff0c;c/c函数调用使用lua调用c/c函数的能力 可以单行执行 已实现if功能 TODO for循环功能 函数功能 单步执行效果图 直接执行效果图 源代码 //0 暂停 1 单步执行 2 断点 //创建…

[无广告!纯干货]免费用CodeFlying自动化生成一个专属的AI机器人

前言&#xff1a; 真心话&#xff0c;花3分钟看文章&#xff0c;再花5分钟体验&#xff0c;你会回来给我点赞的。 随着AIGC&#xff08;人工智能生成内容&#xff09;行业的迅猛发展&#xff0c;人工智能正在以前所未有的速度和方式改变我们的生活。 它不仅在娱乐、教育、医疗…

[数据集][目标检测]游泳者溺水检测数据集VOC+YOLO格式8275张4类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;8275 标注数量(xml文件个数)&#xff1a;8275 标注数量(txt文件个数)&#xff1a;8275 标注…

汇聚荣拼多多电商好不好?

拼多多电商好不好?这是一个值得探讨的问题。拼多多作为中国领先的电商平台之一&#xff0c;以其独特的商业模式和创新的营销策略吸引了大量用户。然而&#xff0c;对于这个问题的回答并不是简单的好或不好&#xff0c;而是需要从多个方面进行综合分析。 一、商品质量 来看拼多…

ONLYOFFICE:开启高效办公新时代的全能利器

ONLYOFFICE官网链接&#xff1a;在线办公套件 | ONLYOFFICE 在线PDF查看器和转换器 | ONLYOFFICE 在数字化办公日益普及的今天&#xff0c;一款高效、易用、功能强大的办公软件成为了企业和个人不可或缺的得力助手。而ONLYOFFICE&#xff0c;正是这样一款集多种功能于一身的优…

Spring系统学习 - 基于注解管理Bean

什么是基于注解的方式管理Bean 在 Spring 框架中&#xff0c;基于注解的方式管理 Bean 是一种非常流行且现代的方法。它允许你通过在类、方法或字段上添加特定的注解来声明 Bean 的创建和依赖注入&#xff0c;从而避免了在 XML 配置文件中定义 Bean 的繁琐工作。 注解和 XML …

Linux开发讲课29---Linux USB 设备驱动模型

Linux 内核源码&#xff1a;include\linux\usb.h Linux 内核源码&#xff1a;drivers\hid\usbhid\usbmouse.c 1. BUS/DEV/DRV 模型 "USB 接口"是逻辑上的 USB 设备&#xff0c;编写的 usb_driver 驱动程序&#xff0c;支持的是"USB 接口"&#xff1a; US…

Linux:系统安全及应用

目录 一、系统账号管理 1.1、系统账号清理 1.2、密码安全控制 1.3、命令历史限制 二、限制su命令用户 三、PAM安全认证 四、sudo机制提升权限 4.1、sudo机制介绍 4.2、用户别名案例 4.3、启用sudo操作日志 4.4、其他案列sudo 4.5、开关机安全控制 4.6、限制更改GR…

无线物联网练习题

文章目录 选择填空简答大题 选择 不属于物联网感知技术的是(A) A:ZigBee B:红外传感器 C:FRID D:传感器 ZigBee是一种无线通信技术&#xff0c;虽然它常用于物联网中作为设备之间的通信手段&#xff0c;但它本身并不是一种感知技术 关于物联网于与互联网的区别的描述&#xff…

昇思第6天

函数式自动微分 神经网络的训练主要使用反向传播算法&#xff0c;模型预测值&#xff08;logits&#xff09;与正确标签&#xff08;label&#xff09;送入损失函数&#xff08;loss function&#xff09;获得loss&#xff0c;然后进行反向传播计算&#xff0c;求得梯度&#…

一站式uniapp优质源码项目模版交易平台的崛起与影响

一、引言 随着信息技术的飞速发展&#xff0c;软件源码已成为推动行业进步的重要力量。源码的获取、交易和流通&#xff0c;对于开发者、企业以及项目团队而言&#xff0c;具有极其重要的意义。为满足市场对高质量源码资源的迫切需求&#xff0c;一站式uniapp优质源码项目模版…

501、二叉搜索树中的众数

给你一个含重复值的二叉搜索树&#xff08;BST&#xff09;的根节点 root &#xff0c;找出并返回 BST 中的所有 众数&#xff08;即&#xff0c;出现频率最高的元素&#xff09;。如果树中有不止一个众数&#xff0c;可以按 任意顺序 返回。 假定 BST 满足如下定义&#xff1…

Java的Object类

概述:所有类的根类(父类),所有的类都会直接或者间接继承Object类 Object中的toString()方法&#xff1a; 如果不重写这个toString方法&#xff1a;默认形式是&#xff1a; return getClass().getName() "" Integer.toHexString(hashCode()); 这个我们可以进到Obj…

鸿蒙开发岗位就业前景分析

在信息技术飞速发展的今天&#xff0c;操作系统作为计算机的灵魂&#xff0c;一直是技术创新和市场竞争的焦点。随着华为鸿蒙操作系统的推出&#xff0c;鸿蒙开发岗位逐渐成为IT行业的热门话题。本文将深入探讨鸿蒙开发岗位的就业前景&#xff0c;揭示这一领域的就业新趋势&…

MSVCR120.DLL丢失的多种修复方法,助你快速解决dll问题

在日常生活和工作中&#xff0c;电脑已经成为我们不可或缺的工具。然而&#xff0c;在使用电脑的过程中&#xff0c;我们常常会遇到一些问题&#xff0c;其中之一就是电脑运行软件时提示找不到msvcr120.dll。如果该文件缺失或损坏&#xff0c;可能会导致依赖它的应用程序无法启…

在WSL Ubuntu中启用root用户的SSH服务

在 Ubuntu 中&#xff0c;默认情况下 root 用户是禁用 SSH 登录的&#xff0c;这是为了增加系统安全性。 一、修改配置 找到 PermitRootLogin 行&#xff1a;在文件中找到 PermitRootLogin 配置项。默认情况下&#xff0c;它通常被设置为 PermitRootLogin prohibit-password 或…

代码随想录算法训练营第55天(py)| 单调栈 | 42. 接雨水*、84.柱状图中最大的矩形

42. 接雨水* 力扣链接 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 思路1 暴力 按列来计算。每一列雨水的高度&#xff0c;取决于&#xff0c;该列 左侧最高的柱子和右侧最高的柱子中&#xff0c;…