C语言标准库与常用工具链:string.h、stdio.h、stdlib.h深度解析与CMake、Makefile构建

C语言标准库与常用工具链:string.h、stdio.h、stdlib.h深度解析与CMake、Makefile构建

《C语言标准库与常用工具链:string.h、stdio.h、stdlib.h深度解析与CMake、Makefile构建》

在这里插入图片描述

一、前言:为什么C标准库与工具链是C语言开发的基石?

学习目标

  • 理解C标准库的本质:C语言的标准函数库,提供了大量常用函数
  • 理解工具链的本质:用于编译、链接和调试C语言程序的工具集合
  • 明确C标准库与工具链的重要性:提高开发效率、简化程序结构
  • 掌握本章学习重点:string.h、stdio.h、stdlib.h的常用函数、CMake与Makefile的构建方法、工具链的使用技巧、避坑指南、实战案例分析
  • 学会使用C标准库编写高效、简洁的程序,使用工具链构建项目

重点提示

💡 C标准库与工具链是C语言开发的基石!通过C标准库,你可以直接使用大量常用函数,避免重复造轮子;通过工具链,你可以简化项目的构建和调试过程。


二、模块1:string.h深度解析——字符串处理的常用函数

2.1 学习目标

  • 理解字符串处理的本质:对字符串进行操作,如复制、拼接、比较
  • 掌握string.h的常用函数:strcpy、strncpy、strcat、strncat、strcmp、strncmp、strlen、strchr、strstr
  • 掌握字符串处理的避坑指南:避免字符串溢出、避免空指针
  • 避开string.h使用的3大常见坑

2.2 string.h的常用函数

字符串复制

#include<string.h>char*strcpy(char*dest,constchar*src);char*strncpy(char*dest,constchar*src,size_t n);

字符串拼接

#include<string.h>char*strcat(char*dest,constchar*src);char*strncat(char*dest,constchar*src,size_t n);

字符串比较

#include<string.h>intstrcmp(constchar*s1,constchar*s2);intstrncmp(constchar*s1,constchar*s2,size_t n);

字符串长度

#include<string.h>size_tstrlen(constchar*s);

代码示例1:使用string.h的常用函数

#include<stdio.h>#include<stdlib.h>#include<string.h>intmain(){char str1[50]="Hello, ";char str2[]="World!";char str3[50];// 字符串复制strncpy(str3, str1,sizeof(str3)); str3[sizeof(str3)-1]='\0';printf("str3: %s\n", str3);// 字符串拼接strncat(str3, str2,sizeof(str3)-strlen(str3)-1);printf("str3: %s\n", str3);// 字符串比较int cmp =strcmp(str1, str2);if(cmp <0){printf("str1 < str2\n");}elseif(cmp >0){printf("str1 > str2\n");}else{printf("str1 == str2\n");}// 字符串长度printf("str1的长度:%lu\n",strlen(str1));// 查找字符char*ptr =strchr(str1,',');if(ptr !=NULL){printf("找到字符 ',' 在位置:%ld\n", ptr - str1);}// 查找子字符串 ptr =strstr(str3,"World");if(ptr !=NULL){printf("找到子字符串 \"World\" 在位置:%ld\n", ptr - str3);}return0;}

三、模块2:stdio.h深度解析——标准输入输出的常用函数

3.1 学习目标

  • 理解标准输入输出的本质:与用户或文件进行数据交换
  • 掌握stdio.h的常用函数:printf、scanf、fprintf、fscanf、fopen、fclose、fread、fwrite
  • 掌握标准输入输出的避坑指南:避免文件打开失败、避免文件读取失败、避免文件写入失败
  • 避开stdio.h使用的3大常见坑

3.2 stdio.h的常用函数

控制台输入输出

#include<stdio.h>intprintf(constchar*format,...);intscanf(constchar*format,...);

文件输入输出

#include<stdio.h> FILE *fopen(constchar*filename,constchar*mode);intfclose(FILE *stream);size_tfread(void*ptr,size_t size,size_t nmemb, FILE *stream);size_tfwrite(constvoid*ptr,size_t size,size_t nmemb, FILE *stream);intfprintf(FILE *stream,constchar*format,...);intfscanf(FILE *stream,constchar*format,...);

代码示例2:使用stdio.h的常用函数

#include<stdio.h>#include<stdlib.h>#include<string.h>typedefstruct{char name[50];int age;float score;} Student;intmain(){ Student students[3]={{"张三",20,90.5},{"李四",21,85.5},{"王五",22,95.5}};// 写文件 FILE *fp =fopen("students.txt","w");if(fp ==NULL){printf("文件打开失败!\n");return0;}for(int i =0; i <3; i++){fprintf(fp,"姓名:%s,年龄:%d,成绩:%f\n", students[i].name, students[i].age, students[i].score);}fclose(fp);// 读文件char buffer[1024]; fp =fopen("students.txt","r");if(fp ==NULL){printf("文件打开失败!\n");return0;}while(fgets(buffer,sizeof(buffer), fp)!=NULL){printf("%s", buffer);}fclose(fp);// 二进制文件读写 fp =fopen("students.dat","wb");if(fp ==NULL){printf("文件打开失败!\n");return0;}fwrite(students,sizeof(Student),3, fp);fclose(fp); Student read_students[3]; fp =fopen("students.dat","rb");if(fp ==NULL){printf("文件打开失败!\n");return0;}fread(read_students,sizeof(Student),3, fp);fclose(fp);printf("二进制文件读取结果:\n");for(int i =0; i <3; i++){printf("姓名:%s,年龄:%d,成绩:%f\n", read_students[i].name, read_students[i].age, read_students[i].score);}return0;}

四、模块3:stdlib.h深度解析——动态内存管理与常用工具函数

4.1 学习目标

  • 理解动态内存管理的本质:在程序运行过程中动态分配和释放内存
  • 掌握stdlib.h的常用函数:malloc、calloc、realloc、free、atoi、atof、rand、srand
  • 掌握动态内存管理的避坑指南:避免内存泄漏、避免空指针、避免访问已释放的内存
  • 避开stdlib.h使用的3大常见坑

4.2 stdlib.h的常用函数

动态内存管理

#include<stdlib.h>void*malloc(size_t size);void*calloc(size_t nmemb,size_t size);void*realloc(void*ptr,size_t size);voidfree(void*ptr);

类型转换

#include<stdlib.h>intatoi(constchar*nptr);doubleatof(constchar*nptr);

随机数

#include<stdlib.h>intrand(void);voidsrand(unsignedint seed);

代码示例3:使用stdlib.h的常用函数

#include<stdio.h>#include<stdlib.h>#include<time.h>intmain(){int*ptr;int size =5;// 动态内存分配 ptr =(int*)malloc(size *sizeof(int));if(ptr ==NULL){printf("内存分配失败!\n");return0;}// 初始化数组srand(time(NULL));for(int i =0; i < size; i++){ ptr[i]=rand()%100;}// 打印数组printf("数组:");for(int i =0; i < size; i++){printf("%d ", ptr[i]);}printf("\n");// 重新分配内存 size =10; ptr =(int*)realloc(ptr, size *sizeof(int));if(ptr ==NULL){printf("内存分配失败!\n");return0;}// 初始化新分配的内存for(int i =5; i < size; i++){ ptr[i]=rand()%100;}// 打印数组printf("数组:");for(int i =0; i < size; i++){printf("%d ", ptr[i]);}printf("\n");// 释放内存free(ptr); ptr =NULL;// 类型转换char str1[]="123";char str2[]="3.14";int num =atoi(str1);double fnum =atof(str2);printf("num:%d,fnum:%f\n", num, fnum);return0;}

五、模块4:CMake与Makefile构建——简化项目的构建过程

5.1 学习目标

  • 理解构建工具的本质:用于管理项目的编译、链接和安装过程
  • 掌握Makefile的编写方法:规则、变量、函数
  • 掌握CMake的使用方法:CMakeLists.txt的编写、构建过程
  • 掌握构建工具的避坑指南:避免语法错误、避免依赖关系错误、避免链接错误
  • 避开构建工具使用的3大常见坑

5.2 Makefile的编写方法

代码示例4:Makefile示例

# 编译器 CC := gcc # 编译选项 CFLAGS := -Wall -Wextra -g # 链接选项 LDFLAGS := -lm # 源文件 SRCS := main.c utils.c # 目标文件 OBJS := $(SRCS:.c=.o) # 可执行文件 TARGET := app .PHONY: all clean all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) %.o: %.c $(CC) $(CFLAGS) -c $< -o $@ clean: rm -f $(OBJS) $(TARGET) 

代码示例5:CMakeLists.txt示例

cmake_minimum_required(VERSION 3.10) project(MyProject) # 设置C标准 set(CMAKE_C_STANDARD 11) # 源文件 set(SRCS main.c utils.c) # 目标可执行文件 add_executable(app ${SRCS}) # 链接库 target_link_libraries(app m) # 安装目标 install(TARGETS app RUNTIME DESTINATION bin) 

六、模块5:工具链的使用技巧——提高开发效率

6.1 学习目标

  • 理解工具链的本质:用于编译、链接和调试C语言程序的工具集合
  • 掌握编译器的使用技巧:gcc的常用选项、优化选项
  • 掌握调试器的使用技巧:gdb的常用命令、断点设置
  • 掌握代码检查工具的使用技巧:valgrind、cppcheck
  • 避开工具链使用的3大常见坑

6.2 工具链的使用技巧

6.2.1 编译器的使用技巧

gcc的常用选项

  • -Wall:显示所有警告
  • -Wextra:显示额外的警告
  • -g:生成调试信息
  • -O2:优化等级2

代码示例6:使用gcc编译程序

gcc -Wall -Wextra -g main.c utils.c -o app -lm 
6.2.2 调试器的使用技巧

gdb的常用命令

  • run:运行程序
  • break:设置断点
  • continue:继续运行
  • next:执行下一行
  • step:进入函数
  • print:打印变量的值

代码示例7:使用gdb调试程序

gdb app 
6.2.3 代码检查工具的使用技巧

valgrind的使用

valgrind --leak-check=yes ./app 

cppcheck的使用

cppcheck main.c utils.c 

七、模块6:实战案例分析——使用C标准库与工具链构建项目

7.1 学习目标

  • 掌握使用C标准库与工具链构建项目:使用string.h、stdio.h、stdlib.h编写程序,使用CMake与Makefile构建项目
  • 学会使用C标准库与工具链解决实际问题
  • 避开实战案例使用的3大常见坑

7.2 使用C标准库与工具链构建项目

项目结构

myproject/ ├── CMakeLists.txt ├── Makefile ├── include/ │ └── utils.h └── src/ ├── main.c └── utils.c 

utils.h

#ifndefUTILS_H#defineUTILS_Hintsum(int*arr,int size);intmax(int*arr,int size);intmin(int*arr,int size);#endif

utils.c

#include"utils.h"intsum(int*arr,int size){int total =0;for(int i =0; i < size; i++){ total += arr[i];}return total;}intmax(int*arr,int size){int maximum = arr[0];for(int i =1; i < size; i++){if(arr[i]> maximum){ maximum = arr[i];}}return maximum;}intmin(int*arr,int size){int minimum = arr[0];for(int i =1; i < size; i++){if(arr[i]< minimum){ minimum = arr[i];}}return minimum;}

main.c

#include<stdio.h>#include<stdlib.h>#include<time.h>#include"utils.h"#defineSIZE10intmain(){int*arr =(int*)malloc(SIZE *sizeof(int));if(arr ==NULL){printf("内存分配失败!\n");return0;}srand(time(NULL));for(int i =0; i < SIZE; i++){ arr[i]=rand()%100;}printf("数组:");for(int i =0; i < SIZE; i++){printf("%d ", arr[i]);}printf("\n");printf("和:%d\n",sum(arr, SIZE));printf("最大值:%d\n",max(arr, SIZE));printf("最小值:%d\n",min(arr, SIZE));free(arr); arr =NULL;return0;}

CMakeLists.txt

cmake_minimum_required(VERSION 3.10) project(MyProject) set(CMAKE_C_STANDARD 11) include_directories(include) set(SRCS src/main.c src/utils.c) add_executable(app ${SRCS}) install(TARGETS app RUNTIME DESTINATION bin) 

构建过程

mkdir build cd build cmake ..make ./app 

八、本章总结与课后练习

8.1 总结

string.h深度解析:字符串处理的常用函数,包括复制、拼接、比较、查找
stdio.h深度解析:标准输入输出的常用函数,包括控制台输入输出和文件输入输出
stdlib.h深度解析:动态内存管理与常用工具函数,包括动态内存分配、类型转换、随机数
CMake与Makefile构建:简化项目的构建过程,提高开发效率
工具链的使用技巧:提高开发效率,包括编译器、调试器、代码检查工具
实战案例分析:使用C标准库与工具链构建项目,实现数组的求和、求最大值、求最小值

8.2 课后练习

  1. 编写程序:使用string.h的函数实现字符串反转
  2. 编写程序:使用stdio.h的函数实现文件的读写
  3. 编写程序:使用stdlib.h的函数实现动态数组的扩容
  4. 编写Makefile:构建一个包含多个源文件的项目
  5. 编写CMakeLists.txt:构建一个包含多个源文件的项目

Read more

解锁DeepSeek潜能:Docker+Ollama打造本地大模型部署新范式

解锁DeepSeek潜能:Docker+Ollama打造本地大模型部署新范式

🐇明明跟你说过:个人主页 🏅个人专栏:《深度探秘:AI界的007》 🏅 🔖行路有良友,便是天堂🔖 目录 一、引言 1、什么是Docker 2、什么是Ollama 二、准备工作 1、操作系统 2、镜像准备 三、安装 1、安装Docker 2、启动Ollama 3、拉取Deepseek大模型 4、启动Deepseek  一、引言 1、什么是Docker Docker:就像一个“打包好的App” 想象一下,你写了一个很棒的程序,在自己的电脑上运行得很好。但当你把它发给别人,可能会遇到各种问题: * “这个软件需要 Python 3.8,但我只有 Python 3.6!

By Ne0inhk
深挖 DeepSeek 隐藏玩法·智能炼金术2.0版本

深挖 DeepSeek 隐藏玩法·智能炼金术2.0版本

前引:屏幕前的你还在AI智能搜索框这样搜索吗?“这道题怎么写”“苹果为什么红”“怎么不被发现翘课” ,。看到此篇文章的小伙伴们!请准备好你的思维魔杖,开启【霍格沃茨模式】,看我如何更新秘密的【知识炼金术】,我们一起来解锁更加刺激的剧情!友情提醒:《《《前方高能》》》 目录 在哪使用DeepSeek 如何对提需求  隐藏玩法总结 几个高阶提示词 职场打工人 自媒体创作 电商实战 程序员开挂 非适用场地 “服务器繁忙”如何解决 (1)硅基流动平台 (2)Chatbox + API集成方案 (3)各大云平台 搭建个人知识库 前置准备 下载安装AnythingLLM 选择DeepSeek作为AI提供商 创作工作区 导入文档 编辑  编辑 小编寄语 ——————————————————————————————————————————— 在哪使用DeepSeek 我们解锁剧情前,肯定要知道在哪用DeepSeek!咯,为了照顾一些萌新朋友,它的下载方式我放在下面了,拿走不谢!  (1)

By Ne0inhk
【AI大模型】DeepSeek + 通义万相高效制作AI视频实战详解

【AI大模型】DeepSeek + 通义万相高效制作AI视频实战详解

目录 一、前言 二、AI视频概述 2.1 什么是AI视频 2.2 AI视频核心特点 2.3 AI视频应用场景 三、通义万相介绍 3.1 通义万相概述 3.1.1 什么是通义万相 3.2 通义万相核心特点 3.3 通义万相技术特点 3.4 通义万相应用场景 四、DeepSeek + 通义万相制作AI视频流程 4.1 DeepSeek + 通义万相制作视频优势 4.1.1 DeepSeek 优势 4.1.2 通义万相视频生成优势 4.2

By Ne0inhk
【DeepSeek微调实践】DeepSeek-R1大模型基于MS-Swift框架部署/推理/微调实践大全

【DeepSeek微调实践】DeepSeek-R1大模型基于MS-Swift框架部署/推理/微调实践大全

系列篇章💥 No.文章01【DeepSeek应用实践】DeepSeek接入Word、WPS方法详解:无需代码,轻松实现智能办公助手功能02【DeepSeek应用实践】通义灵码 + DeepSeek:AI 编程助手的实战指南03【DeepSeek应用实践】Cline集成DeepSeek:开源AI编程助手,终端与Web开发的超强助力04【DeepSeek开发入门】DeepSeek API 开发初体验05【DeepSeek开发入门】DeepSeek API高级开发指南(推理与多轮对话机器人实践)06【DeepSeek开发入门】Function Calling 函数功能应用实战指南07【DeepSeek部署实战】DeepSeek-R1-Distill-Qwen-7B:本地部署与API服务快速上手08【DeepSeek部署实战】DeepSeek-R1-Distill-Qwen-7B:Web聊天机器人部署指南09【DeepSeek部署实战】DeepSeek-R1-Distill-Qwen-7B:基于vLLM 搭建高性能推理服务器10【DeepSeek部署实战】基于Ollama快速部署Dee

By Ne0inhk