C提高
C语言提高篇
Scarlett2025
种一棵树最好的时间是十年前,其次是现在。——非洲经济学家Dambisa Moyo《dead aid》
展开
-
预处理指令
头文件包含 #include 注意 “” <> 区别 <> 系统头文件 “” 自定义头文件 宏定义 不重视作用域 可以利用 #undef 卸载宏 宏常量 没有数据类型 宏函数 要注意表达式完整性 void test01(){#define MAX 1024 //#undef MAX} 条件编译 测试存在 #ifdef 测试不存在 #ifndef 自定义条件测试 #if //#de......原创 2022-05-27 17:58:43 · 2153 阅读 · 0 评论 -
递归函数案例
函数自身调用自身,必须有结束条件退出循环 案例 实现字符串逆序遍历 //1、实现字符串逆序遍历void reversePrint(char * p){ if (*p == '\0') { return; //退出条件 } reversePrint(p + 1); printf("%c ", *p);}void test01(){ char * str = "abcdef"; reversePrint(str);}//2、实现字符串正序遍历void Posi原创 2022-05-27 17:07:03 · 188 阅读 · 0 评论 -
动态库配置流程
静态库优缺点 优点 : 生成的exe程序中包含了 静态库中的内容,与静态库无瓜葛 缺点 : 浪费资源 , 更新发布比较麻烦 动态库 运行阶段才去链接函数 配置流程: 创建项目 --- 配置属性 -- 常规 --- 配置类型 --- 动态库 重新生成解决方案,生成 .dll .lib 库文件 导入函数 只能在当前项目下使用 导出函数 可以在外部使用 __declspec (dllexport) int mySub(int a, int b); ...原创 2022-05-27 16:42:37 · 292 阅读 · 0 评论 -
静态库配置流程
创建项目 --- 配置属性 --- 常规 ----- 配置类型 --- 静态库 重新生成项目 ,创建出后缀名为 .lib的静态库文件 测试静态库重新生成解决方案 Ctrl+Shift+B在程序中直接使用静态库中的函数即可,此时会出现警告在程序中引入.h头文件即可...原创 2022-05-27 15:28:41 · 177 阅读 · 0 评论 -
回调函数案例
#include<stdio.h>#include <stdlib.h>void selectSort(int *p, int n,int(*pf)(int,int)) { for (int i = 0; i < n - 1; i++) { for (int j = i + 1; j < n; j++) { if (pf(p[i] ,p[j])) { p[i] = p[i] ^ p[j]; p[j] = p[i] ^原创 2021-12-22 17:04:30 · 609 阅读 · 0 评论 -
函数指针的定义
先定义出函数类型,再通过类型定义出函数指针 typedef void(FUNC_TYPE)(); FUNC_TYPE * pFunc = func; 先定义出函数指针类型,再定义函数指针 typedef void(*FUNC_TYPE)(); FUNC_TYPE pFunc = func; 直接定义函数指针变量 void(* pFunc )() = func; 函数指针和指针函数的区别 //函数指针 是指向函数的 指针 //指针函数 函数的返回值是一个指针.....原创 2022-05-26 16:07:32 · 2290 阅读 · 0 评论 -
链表的基本使用
带头节点链表 好处在于 头节点永远都是固定的 初始化链表 struct LinkNode * pHeader = init_LinkList () 遍历链表 void foreach_LinkList( struct LinkNode * pHeader ) 插入链表 void insertLinkList( struct LinkNode*pHeader , int oldval ,int newval ) 在oldval前插入 newVal,如果没有oldval就进行尾插 ...原创 2022-05-26 15:44:43 · 158 阅读 · 0 评论 -
链表的基本概念
链表引出 数组有缺陷 静态空间,一旦分配内存就不可以动态扩展,要不分配不够,要不分配过多 对于数组头部进行插入和删除效率低 链表的组成 链表是由节点组成的 节点由 数据域 和 指针域组成 struct LinkNode { int num ; struct LinkNode * next; } 链表的分类 方式1 静态链表 动态链表 方式2 单向链表 双向链表 单向循环链表 双向循环链表 ...原创 2022-05-26 13:51:31 · 169 阅读 · 0 评论 -
文件加密和解密实现
code.h#define _CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<string.h>#include<stdlib.h>//加密void codeFile(char * sourceFile, char * destFile);//解密void deCodeFile(char * sourceFile, char * destFile);code.c#include"code..原创 2022-05-26 11:43:53 · 542 阅读 · 0 评论 -
配置文件读写
需求:将文件中的有效内容截取出来,并且放入到一个键值对的数组中 struct ConfigInfo { char key[64] ; char value[64] }; 获取有效行数 判断当前行是否有效 解析数据 parseFile 将有效数据放入到数组中,数组在堆区开辟 根据key获取value getInfoByKey 释放内存 freeSpaceconfig.h#pragma once#define _CRT_SECURE_NO_WARNINGS...原创 2022-05-25 17:26:48 · 354 阅读 · 0 评论 -
文件读写注意事项
当按照字符的方式读文件时候,通常利用判断EOF获取是否读到文件尾 当对自定义数据类型写入文件时,不要将指针写入到文件里,要将指针指向的内容写入#define _CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<string.h>#include<stdlib.h>void test01(){ FILE * file = fopen("./test.txt", "r"); if (file == NU..原创 2022-05-25 14:31:03 · 288 阅读 · 0 评论 -
文件读写方式
按照字符进行读写 写文件 fputc 读文件 fgetc 文件结尾 EOF END OF FILE void test01(){ //写文件 FILE * f_write = fopen("./test1.txt", "w"); if (f_write == NULL) { return; } char buf[] = "hello world"; for (int i = 0; i < strlen(buf); i++) { fputc(...原创 2022-05-25 13:46:54 · 260 阅读 · 0 评论 -
内存对齐知识
内存对齐原因:以空间换时间 对于自定义数据类型对齐规则: //1、从第一个属性开始 偏移为0 //2、第二个属性开始,地址要放在 该类型整数倍 与 对齐模数比 取小的值 的整数倍上 //3、所有的属性都计算结束后,整体再做二次对齐,整体需要放在属性中最大类型 与 对齐模数比 取小的值的整数倍上 如果查看对齐模数 #pragma pack(show) 默认对齐模数 是8,可以将对齐模数改为 2的n次方 当结构体嵌套结构体时候,只需要看子结构体中最大数据类型就可以了...原创 2022-05-20 17:37:27 · 149 阅读 · 0 评论 -
结构体偏移量
可以利用offsetof来计算结构体中属性的偏移 也可以通过地址的相加运算 计算偏移量 结构体嵌套结构体#include <stddef.h>struct Person{ char a; // 0 ~ 3 int b; // 4 ~ 7};void test01(){ struct Person p1; struct Person * p = &p1; printf("b的偏移量为: %d\n", (int)&(p->b...原创 2022-05-20 17:19:18 · 509 阅读 · 0 评论 -
结构体嵌套二级指针练习
#define _CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<string.h>#include<stdlib.h>struct Teacher{ char * name; char ** Students;};void allocateSpace(struct Teacher *** teachers){ struct Teacher ** pArray = malloc(sizeof(s原创 2022-05-20 17:08:11 · 178 阅读 · 0 评论 -
结构体嵌套一级指针练习
设计结构体 struct Person { char * name,int age } 在堆区创建 结构体指针数组 malloc(sizeof(struct Person *) * 3); 给每个结构体也分配到堆区 给每个结构体的姓名分配到堆区 打印数组中所有人的信息 释放堆区数据struct Person{ char * name; int age;};struct Person ** allocateSpace(){ struct Person ** pA...原创 2022-05-20 15:27:38 · 110 阅读 · 0 评论 -
结构体赋值问题以及解决
系统提供的赋值操作是简单的值拷贝,逐字节拷贝---- 浅拷贝 如果属性中有指向堆区的内容,在释放期间会导致堆区重复释放,并且还有内存泄露 解决方案:利用深拷贝,手动赋值 struct Person{ char name[64]; int age;};void test01(){ struct Person p1 = { "Tom", 18 }; struct Person p2 = { "Jerry", 20 }; p1 = p2; printf("p1的姓名: %..原创 2022-05-20 14:52:35 · 585 阅读 · 0 评论 -
结构体的基本使用
如果有typedef 定义结构体,那么后面跟着的单词是类型的别名 typedef struct Person{ char name[64]; int age; //不要在定义结构体时候赋初值} myPerson;//myPerson是struct Person 类型的别名void test01(){ myPerson p = { "aa", 10 };} 没有typedef,定义结构体,后面跟着的单词是一个结构体变量 struct Person2{ char n..原创 2022-05-20 14:21:38 · 328 阅读 · 0 评论 -
指针数组排序实现
选择排序 假设排序规则为从小到大 先认定一个最小值下标为i,通过j = i+1找的真实最小值下标 判断计算出的真实最小值下标 和开始认定的i是否相等,如果不相等,交换i和min下标的两个元素 对指针数据进行从大到小排序//从小到大 选择排序void selectSort01(int arr[], int len){ for (int i = 0; i < len; i++) { int min = i; //定义出最小值的下标 for (int j = i +..原创 2022-05-20 14:06:50 · 2924 阅读 · 0 评论 -
二维数组名称
除了两种特殊情况外,都是指向第一个一维数组的指针 两种特殊情况 sizeof 统计整个二维数组长度 对数组名称取地址 int(*p2)[3][3] = &arr; void test01(){ //可读性高 int arr[3][3] = { {1,2,3}, {4,5,6}, {7,8,9} }; //int arr2[3][3] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; //int arr3[][3] = { 1, 2, ...原创 2022-05-19 17:44:12 · 245 阅读 · 0 评论 -
数组指针的定义
先定义出数组的类型,再通过类型创建数组指针 typedef int(ARRAY_TYPE)[5]; void test01(){ int arr[5] = { 1, 2, 3, 4, 5 }; typedef int(ARRAY_TYPE)[5]; // ARRAY_TYPE是一个数据类型,代表有5个int类型元素的数组 ARRAY_TYPE *arrP = &arr; //printf("%d\n", arrP); //printf("%d\n", arr...原创 2022-05-19 15:56:29 · 1631 阅读 · 0 评论 -
一维数组名称
本质并不是一个指针 有两种特殊情况 对数组名称进行sizeof 对数组名称 取地址 ,获取的指针步长是整个数组长度 除了两种特殊情况外,都是指向数组中首元素的地址 的指针 数组名--- 指针常量,指针的指向不可以修改 如果将数组名传入到函数参数中,为了提高可读性通常写为 int arr[] 访问数组元素时候,下标可以为负数void printArray(int arr[], int len)// int arr[] 等价于 int * arr{ for (int i =原创 2022-05-19 15:40:59 · 270 阅读 · 0 评论 -
位运算&移位运算
按位取反 ~ 0变1 1变1 void test01(){ int num = 2; printf("~num = %d\n", ~num); // -很大 -2 253 1 -很小 +很大 -3 // 010 按位取反 101 源码 // 101 补码 110 + 1 = 111} 按位与 & 全1为1 一0为0 void test02(){ int num = 124; if ((...原创 2022-05-17 23:00:45 · 123 阅读 · 0 评论 -
二级指针练习-文件读写
需求:从文件中读取数据,并且将数据存放到堆区的数组中 char ** pArray = malloc(sizeof(char *) * len ) 获取有效行数 将文件光标置为文件首 fseek(file , 0 ,SEEK_SET) 读取文件数据并且放入到pArray中 显示数组pArray 释放数组pArray#define _CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<string.h>...原创 2022-05-17 22:30:28 · 123 阅读 · 0 评论 -
二级指针做函数参数的输入输出特性
输入特性 在主调函数分配内存,被调函数使用 在堆区创建 #define _CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<string.h>#include<stdlib.h> 二级指针做函数参数的输入特性 主调函数分配内存,被调函数使用 void printArray(int ** pArray, int len){ for (int i = 0; i < len; i++) {原创 2022-05-17 21:54:46 · 171 阅读 · 0 评论 -
const的使用场景
用来修饰函数中的形参,防止误操作#define _CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<string.h>#include<stdlib.h>struct Person{ char name[64]; int age; int Id; double score;};//const使用场景,修饰函数中的形参,防止误操作void printPerson(const struct Perso原创 2022-05-17 19:50:09 · 263 阅读 · 0 评论 -
查找子串及指针的易错点
实现自己的查找子串功能,需求在字符串中查找对应的子串,如果有返回字符串第一个字母的位置,如果没有返回-1#define _CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<string.h>#include<stdlib.h>//优化思路 memcmp( str,substr,3) == 0int myStrstr( char * str , char * subStr ){ int num = 0;原创 2022-05-16 21:18:47 · 188 阅读 · 0 评论 -
读取文本格式配置文件内容
/* *parameter: cfgfilepath 文件的绝对路径名如: /user/home/my.cfg * key 文本中的变量名 * value 对应变量的值,用于保存 * */#include <iostream>#include <string>#include <fstream>using namespace std;static bool readConfigFi原创 2022-05-13 11:56:00 · 178 阅读 · 0 评论 -
sscanf的使用
将已知的字符串通过格式化匹配出有效信息案例 字符串 char * str = “abcde#zhangtao@12345” 中间的zhangtao匹配出来 匹配char * ip = “127.0.0.1”将中间数字匹配到 num1 ~ num4中原创 2022-04-24 12:08:37 · 2084 阅读 · 0 评论 -
calloc和realloc
calloc和malloc一样都是在堆区分配内存 不同点在于 calloc 会将分配的内存初始化为0 realloc重新在堆区分配内存 如果分配的内存比原来要大,这个时候有两种情况出现 原有空间后序有足够大的空闲空间,那么直接在原有空间后继续开辟内存,返回原有空间的首地址 原有空间后序没有足够大空闲空间,重新会分配一个足够大的空间,并且将原有空间的内容拷贝到新空间下,释放原有空间,将新空间的首地址返回 void test01(){ int * p = malloc(sizeof(in原创 2022-04-21 22:04:51 · 288 阅读 · 1 评论 -
sprintf格式化字符串
可以利用sprintf对字符串进行格式化 sprintf(目标字符串, "格式",占位参数…);格式化字符串void test01(){ char buf[1024]; memset(buf, 0, 1024); sprintf(buf, "今天是%d年 %d月 %d 日\n", 2018, 5, 6); printf("%s", buf);}拼接字符串void test02(){ memset(buf, 0, 1024); char str1[] = ..原创 2022-04-20 22:35:00 · 1304 阅读 · 0 评论 -
字符串强化训练-拷贝字符串|字符串反转实现
字符串是有结束标志 \0 利用三种方式对字符串进行拷贝 利用[] 利用指针 利用while (*dest++ = *source++){} 利用两种方式对字符串进行反转 利用[] 利用指针原创 2022-04-20 20:43:20 · 288 阅读 · 0 评论 -
指针做函数参数的输入输出特性
输入特性: 在主调函数中分配内存,被调函数使用 输出特性: 被调函数中分配内存,主调函数使用 void func(char * p){ strcpy(p, "helloworld");}void test01(){ //分配到栈上 char buf[1024] = { 0 }; func(buf); printf("%s\n", buf);}void printString(char * str){ printf("%s\n", str);}vo.原创 2022-04-19 21:50:51 · 124 阅读 · 0 评论 -
指针的间接赋值
满足条件 通过 * 进行赋值 建立关系 一个普通变量和一个指针变量(或者一个实参一个形参)原创 2022-04-19 21:31:10 · 255 阅读 · 0 评论 -
指针的步长
指针变量+1 之后 跳跃的字节数量 解引用的时候,取的字节数 对自定义数据类型进行练习 如果获取自定义数据类型中属性的偏移 offsetof( 结构体 , 属性 ) 头文件 #include<stddef.h> void test01(){ char * p = NULL; printf("%d\n", p); printf("%d\n", p + 1); double * p2 = NULL; printf("%d\n", p2); printf("%d.原创 2022-04-19 16:23:03 · 518 阅读 · 0 评论 -
空指针和野指针
空指针 不允许向NULL和非法地址拷贝内容 野指针 未初始化指针 malloc后也free了,但是指针没有置空 指针操作超越变量作用域 空指针可以释放 ,但是野指针不可以释放...原创 2022-04-14 22:20:46 · 163 阅读 · 0 评论 -
函数调用流程、栈的生成方向以及内存存储方式
函数调用流程宏函数 优点: 以空间换时间 将比较频繁短小的函数 写为宏函数,直接跑源码 在一定程度上会比普通函数效率高,普通函数会有入栈和出栈的时间开销 调用惯例 主调函数和被调函数都必须有一致的约定,才可以正确的调用函数,这个约定我们称为调用惯例 调用惯例包含的内容: 出栈方、参数的传入顺序、函数名称的修饰 c和c++下默认的调用惯例为 cdecl #define _CRT_SECURE_NO_WARNINGS#include<stdio.h>#in..原创 2022-04-13 20:53:39 · 233 阅读 · 0 评论 -
数据区的变量及常量
放入是静态变量、全局变量、常量static 和 extern 区别static 静态变量:编译阶段分配内存,只能在当前文件内使用,只初始化一次static int a = 10; //特点:只初始化一次,在编译阶段就分配内存,属于内部链接属性,只能在当前文件中使用void test01(){ static int b = 20; //局部静态变量,作用域只能在当前test01中 //a 和 b的生命周期是一样的}extern 全局变量,C语言下默认的全局变量前都隐原创 2022-04-10 22:17:10 · 272 阅读 · 0 评论 -
内存分区(堆区、栈区及注意事项)
内存分区 运行前 代码区 共享的 只读的 数据区 data 已初始化的全局变量、静态变量、常量 bss 未初始化的全局变量、静态变量、常量 运行后 栈区 属于先进后出的数据结构 由编译器管理数据开辟和释放 变量的生命周期在该函数结束后自动释放掉 堆区 容量远远大于栈 没有先进后出这样的数据结构 由程序员管理开辟和管理释放 malloc、free 记...原创 2022-04-10 21:02:45 · 1323 阅读 · 0 评论 -
变量的修改方式
内置数据类型void test01(){ int a = 10; //直接修改 a = 20; printf("a = %d\n", a); //间接修改 int * p = &a; *p = 100; printf("a = %d\n", a);}对于自定义数据类型struct Person{ char a; // 0 ~ 3 int b; // 4 ~ 7 char c; // 8 ~ 11 int d; // 12 ~ 15};void原创 2022-04-09 21:52:04 · 544 阅读 · 0 评论