前言本系列C语言教程将补充C语言的基础部分适合具有一定语言基础的朋友进行复习。第一期 【C语言简明教程】(一):数据类型,表达式与控制结构-CSDN博客第二期 【C语言简明教程提纲】(二)函数你值得拥有-CSDN博客以下是本系列的目录字符串使用本节编译预处理本节数组与函数数组定义和引用指针定义和使用指针与数组、与字符串、与函数结构体定义、结构体数组、结构体指针文件定义和操作。常用算法关于数值和指针两个难点可以参考之前写的文章浅显易懂适合初学者的朋友【C语言备课课件】上数组array【C语言备课课件】下指针pointer0 前置知识-进制转换0-1 进制表在 C 语言中字符串的八进制转义字符和十六进制转义字符本质上是ASCII 数值表示因此需要简单了解进制转换。0-2 十六进制 → 十进制手算方法十六进制的基数是16。0~9和a~f计算方法每一位 × 16 的幂 每一位 × 16 的幂每一位×16的幂例如0 x 41 0x410x41计算就是4×16¹1×16⁰641650-3 八进制 → 十进制手算方法同样的道理八进制基数是8。0~7计算方法每一位 × 8 的幂 每一位 × 8 的幂每一位×8的幂例如141 ( 八进制 ) 141(八进制)141(八进制)计算就是:1×8²4×8¹1×8⁰64321971 字符串使用1-1 字符串定义在 C 语言中并没有专门的string类型字符串本质上是字符数组并且以\0空字符作为结束标志。charstr[]hello;//等价写法charstr[]{h,e,l,l,o,\0};在内存中实际存储为h e l l o \0\0非常重要它表示字符串结束许多字符串函数都是依靠它来判断字符串长度的。sizeof(str)61-2 自定义字符串长度字符串长度可以通过遍历\0计算。#includestdio.hunsignedintmyStrlen(charstr[]){unsignedinti0;while(str[i]!\0){i;}returni;}intmain(){charstr[]hello;printf(字符串的长度为%u,myStrlen(str));return0;}当然我们平常肯定用内置的函数1-3 常用字符串函数C 语言在string.h中提供了许多字符串处理函数。#includestring.h常用函数如下函数作用strlen(str)计算字符串长度strcpy(a,b)字符串复制strcat(a,b)字符串连接strcmp(a,b)字符串比较strlen:计算字符串长度(不计算 \0)charstr[]hello;printf(%d,strlen(str));sizeof(str)//- 包含 \0 的数组总大小strlen(str)//- 不包括 \0 的字符长度strcpy:字符串复制。chara[20];charb[]hello;strcpy(a,b);strcat:字符串连接.chara[20]hello ;charb[]world;strcat(a,b);strcmp:字符串比较printf(%d,strcmp(abc,abd));返回值含义0两字符串相等0a b0a b1-4 字符串数组可以定义字符串数组存储多个字符串。charstr[3][10]{apple,banana,orange};2 转义字符2-1 定义在字符串中有些字符无法直接通过键盘输入或者具有特殊含义这时就需要使用转义字符Escape Character。转义字符以反斜杠\开头。例如printf(hello\nworld);其中的\n表示换行符。2-2 常见转义字符转义字符含义\n换行\t水平制表符Tab\\输出反斜杠\\输出双引号\输出单引号\0字符串结束符举例printf(hello\nworld\n);printf(hello\tworld\n);printf(\\n 表示换行\n);输出hello world hello world \n 表示换行2-3 八进制转义字符转义字符还可以表示ASCII 码字符。格式如下\ooo其中ooo为 1~3 位八进制数举例printf(\141\n);输出结果为a因为141(八进制) 97(十进制)而ASCII 码97对应字符为a2-4 十六进制转义字符格式如下\xhh其中hh为十六进制数举例printf(\x61\n);输出结果为a,因为61(十六进制) 97(十进制)2-5 复杂例子我们来看一个稍复杂的例子chars[]a\128b\\\tcd\xdg\n;printf(%d,strlen(s));展开分析为a \12//(八进制转义字符只能使用数字 0~7)8b \//(//转义为一个/)\t c d \xd//十六进制转义字符只能使用0~9 A~F a~fg \n故答案为113 字符串输入在 C 语言中字符串本质是字符数组所以输入字符串的方式和数组类似。常用方法主要有:scanfgets不推荐fgets安全推荐3-1 使用scanf输入字符串#includestdio.hintmain(){charstr[20];printf(请输入字符串);scanf(%s,str);printf(你输入的字符串是%s\n,str);return0;}注意事项%s会自动在字符串末尾加上\0遇到空格就结束输入3-2 使用gets不推荐charstr[20];gets(str);特点可以读取空格遇到换行符\n就停止读取不安全无法限制输入长度容易导致缓冲区溢出gets函数已经被弃用3-3 使用fgets安全推荐#includestdio.hintmain(){charstr[20];printf(请输入字符串);fgets(str,sizeof(str),stdin);printf(你输入的字符串是%s,str);return0;}说明第一个参数是存储字符串的数组第二个参数是数组大小第三个参数是输入流一般为stdin遇到换行符\n就停止读取会把换行符\n一起读入如果不想要可以用str[strcspn(str,\n)]\0;3-5 字符输出函数3-5-1getchar()函数功能从标准输入通常是键盘读取 一个字符返回类型为 int。函数原型intgetchar(void);示例#includestdio.hintmain(){intc;printf(请输入一个字符);cgetchar();// 读取一个字符printf(你输入的字符是%c\n,c);return0;}注意事项返回类型为 int而不是 char是为了能表示 EOF-1。每次调用只读取 一个字符包括空格、换行符。可以配合循环逐个处理字符intch;while((chgetchar())!EOF){putchar(ch);// 回显输入的字符}3-5-2putchar()函数功能向标准输出通常是屏幕输出 一个字符。函数原型intputchar(intc);示例#includestdio.hintmain(){charchA;putchar(ch);// 输出 Aputchar(\n);// 输出换行return0;}特点每次只能输出一个字符。可以与 getchar 搭配使用实现字符回显或处理#includestdio.hintmain(){intch;printf(输入字符按 CtrlD (Linux) 或 CtrlZ (Windows) 结束\n);while((chgetchar())!EOF){putchar(ch);// 输出输入的字符}return0;}4 字符串与字符数组4-1 定义区别字符数组charstr1[]{h,e,l,l,o,\0};字符串字面量指针char*str2hello;特性char str[]char *str存储位置数组在栈局部变量或全局区字符串字面量在只读区是否可修改可修改如str[0]H不可修改修改会导致未定义行为长度计算可用sizeof(str)得到数组大小sizeof(str)得到指针大小需要strlen(str)4-2与函数结合数组名作为实参传递voidprintArray(chararr[]){...}printArray(str1);// 传递的是首元素地址修改函数内部的内容会影响原数组voidmodify(chararr[]){arr[0]H;}modify(str1);// str1[0]变为H字符串字面量指针传入函数voidmodify(char*s){s[0]H;// 未定义行为通常会崩溃}modify(str2);5 编译预处理5-1 定义编译预处理Preprocessing是 C 语言编译的第一步在正式编译前会进行宏定义展开头文件包含条件编译行号信息处理预处理由预处理器cpp完成指令以#开头。5-2 常用预处理指令指令作用示例#define定义宏#define PI 3.14#undef取消宏定义#undef PI#include引入头文件#include stdio.h#if/#ifdef/#ifndef/#else/#elif/#endif条件编译见示例#error报错信息#error 必须定义宏#pragma特定编译器指令#pragma once5-3 宏函数宏函数Macro Function其实是通过#define定义的带参数的宏它本质上并不是函数而是在预处理阶段进行文本替换。语法#define宏名(参数1,参数2,...)替换内容例子#defineSQUARE(x)((x)*(x))这里SQUARE(x)是宏函数(x)*(x))防止宏被放到更复杂表达式中时优先级错误。宏展开时会直接替换inta5;intbSQUARE(a);// 编译前会变成 ((a)*(a))特性说明预处理展开宏函数在编译前被展开为文本不会生成函数调用无类型检查宏参数不会检查类型容易出错效率高没有函数调用开销但可能导致代码膨胀可能产生副作用如果参数中有表达式可能被重复计算总之这东西一般不太可能会用((了解为主))特性宏函数普通函数调用开销无有函数调用开销类型检查无有类型检查编译阶段预处理阶段编译/链接阶段表达式副作用可能重复计算安全不重复5-3-1 宏函数题目为什么会考这种啊喂定义一个宏用于判断所给出年份是否喂闰年#defineLEAP_YEAR(y)((((y)%100!0)((y)%40))||((y)%4000))5-4 条件编译C 语言提供几个常用的条件编译指令指令作用#if 常量表达式如果表达式非零编译该代码块#ifdef 宏名如果宏已定义编译该代码块#ifndef 宏名如果宏未定义编译该代码块#elif 常量表达式#if的 else-if 分支#else前面的条件都不满足时编译该代码块#endif结束条件编译块5-4-1ifdef#includestdio.h#defineDEBUGintmain(){#ifdefDEBUGprintf(调试模式开启\n);#endifprintf(程序运行\n);return0;}输出调试模式开启 程序运行如果注释掉#define DEBUG就不会输出“调试模式开启”。5-4-2ifndef#ifdef/#ifndef仅检查宏是否定义不考虑宏值#includestdio.h#ifndefVERSION#defineVERSION1#endifintmain(){printf(版本号: %d\n,VERSION);return0;}如果VERSION未定义则定义为 1。如果已经定义则保留原定义。5-4-3#if / #elif / #else / #endif#if/#elif需要常量表达式不可以直接写变量。#includestdio.h#definePLATFORM2intmain(){#ifPLATFORM1printf(Windows 平台\n);#elifPLATFORM2printf(Linux 平台\n);#elseprintf(其他平台\n);#endifreturn0;}5-5 文件包含系统头文件#includestdio.h用户自定义头文件#includemyheader.h区别 系统目录查找 先当前目录再系统目录查找5-6 常用头文件头文件主要内容stdio.h输入输出函数如printf(),scanf(),fgets(),fputs()stdlib.h常用工具函数如malloc(),free(),exit(),atoi(),rand()string.h字符串处理函数如strlen(),strcpy(),strcat(),strcmp(),memset(),memcpy(),memcmp()math.h数学函数如sqrt(),pow(),sin(),cos(),fabs()ctype.h字符处理函数如isdigit(),isalpha(),toupper(),tolower()time.h时间函数如time(),clock(),difftime(),strftime()limits.h定义各种数据类型的边界值如INT_MAX,CHAR_MINfloat.h定义浮点数相关的边界如FLT_MAX,DBL_MINstdbool.h布尔类型支持true和falseassert.h断言宏assert()用于调试小结本节主要介绍了 C 语言的字符串使用、转义字符、字符串输入与数组区别以及编译预处理相关内容包括宏定义、宏函数、条件编译和头文件包含。下一节我们将从结构体开始如有错误欢迎指出!