导图社区 《C语言程序设计》思维导图(第二版)
网上一大堆的C语言导图,但都是知识点的罗列,尤其是数组和指针的内在关系,都没有说清楚。本导图首次阐述了数组首地址、数组地址的区别,及其和指针的内在逻辑。这是最好的C语言程序设计思维导图,既适合新手入门,也适合高手作为资料查询。
编辑于2022-01-05 17:26:34联网双创大赛项目基本思路思维导图。导图包括学生打游戏给社会带来极大负担、我们发现无法有效控制的原因是存在n个问题没有解决、该产品的应用推广情况、我们为保护该产品做了哪些工作、公司进展和规划、公司能为社会带来哪些效益等内容。
网上一大堆的C语言导图,但都是知识点的罗列,尤其是数组和指针的内在关系,都没有说清楚。本导图首次阐述了数组首地址、数组地址的区别,及其和指针的内在逻辑。这是最好的C语言程序设计思维导图,既适合新手入门,也适合高手作为资料查询。
本思维导图源自省级教坛新秀的省级示范课内容。首次明确了数组首地址和数组地址的定义,并详细比较其内涵和用法。从全新的角度阐述了数组、指针、函数的数据类型和内在关系。把C语言的最难点史无前例的用2个图清晰的展示出来。指针因为本图而不难!
社区模板帮助中心,点此进入>>
联网双创大赛项目基本思路思维导图。导图包括学生打游戏给社会带来极大负担、我们发现无法有效控制的原因是存在n个问题没有解决、该产品的应用推广情况、我们为保护该产品做了哪些工作、公司进展和规划、公司能为社会带来哪些效益等内容。
网上一大堆的C语言导图,但都是知识点的罗列,尤其是数组和指针的内在关系,都没有说清楚。本导图首次阐述了数组首地址、数组地址的区别,及其和指针的内在逻辑。这是最好的C语言程序设计思维导图,既适合新手入门,也适合高手作为资料查询。
本思维导图源自省级教坛新秀的省级示范课内容。首次明确了数组首地址和数组地址的定义,并详细比较其内涵和用法。从全新的角度阐述了数组、指针、函数的数据类型和内在关系。把C语言的最难点史无前例的用2个图清晰的展示出来。指针因为本图而不难!
《C语言程序设计》 思维导图笔记
约定
非特殊说明,实例程序及结果是在Dev C++5.11(64bit)版运行通过的
[]括着的表示可选项
所述的教材为:C程序设计(第五版)
C语言最简结构
#include <stdio.h> int main() { //insert your code here; return 0; }
基于C99标准
C语句必须以英文分号";"结尾。
1. 规范:一行的语句数量不超过1句;因此在换行时应检查行尾是否有分号。
2. 括号、引号应成对输入。然后通过方向键或鼠标移动到括号或引号内继续输入。
3. #include <stdio.h> 为预编译指令,不是C语句所以行尾不能加分号。
printf
所在库
stdio.h
原型
int printf(const char * format,...);
调用格式
printf("输出字符串",输出列表);
注意:输出字符串要用英文的双引号引上,与输出列表之间用英文逗号隔开 输出列表中的各项之间也用英文逗号隔开。
例:printf("%d, %c",123,var); //var是一个字符型变量
字符串
1. 普通字符串
原样输出
2. 转义字符
1. 转义输出,以\开头。
2. 常见转义字符及含义
\n:换行符
\b:退格符
\t:横向制表符
\\:反斜杠
\":双引号
其他的见教材第40页
3. 格式字符串
1. 以%开头,与输出列表一一对应
2. %[flags][width][.precision][length]Type
3. Type
d,i:输出十进制有符号数
u:输出十进制无符号数
o/lo:输出八进制无符号数
x/X:输出十六进制无符号数,x对应abcdef,X对应ABCDEF
f/lf:输出单精度/双精度浮点数
e/E:以指数形式输出实数,e表示小写(如:1.2e+02),E表示大写(如:1.2E+02)
g/G:选用%f或%e格式中输出宽度较短的一种格式,不输出无意义的0
c:字符型输出。可以把输入的数字按照ASCII码相应转换为对应的字符
s:输出字符串。输出字符串中的字符直至字符串中的'\0'
4. flags
-:减号,输出结果左对齐,右边填空格。默认右对齐,左边填空格
+:加号,输出正负号
:空格,输出正数时加上空格,输出负数时添加符号
#:井号,type为o,x,X时,添加前缀0,0x,0X type为e,E,g,G时,强制输出小数点。默认情况下:如果使用.0控制不输出小数点 type为g/G时,保留尾部的0
0:数字0,指定列宽不满时,前面补0
5. width
十进制整数:指定输出宽度,不足时补0。printf("%6d",1000),输出:001000
0*:在输出列表中指定输出宽度。printf("%0*d",6,1000),输出:001000
6. .precision
以.开头,后跟十进制数
对于整型,表示输出的最小数字个数,不足补0,超过不截断。
对于e/E,f/lf,表示小数点后数值位数,不足补零,超过截断。默认为6位
对于g/G,表示最大有效数字
对于字符串s,表示最大输出字符数,不足正常输出,超过则截断。
不显式指定,默认位0
.* 在输出列表中指定精度
基本数据类型 (DataType)
基本类型
整型
[unsigned] char
[unsigned] short int
[unsigned] int
[unsigned] long int
[unsigned] long long int
1. 在Dev C++中,长度依次为:1、2、4、4、8 2. 整型均有无符号和有符号之分。 3. 整型的长度须满足: long long int >= long int >= int >= short int 4. 测试方法:printf("%d",sizeof(int)); 输出4;说明int的长度为4个字节
bool:C99中规定的数据类型,但Dev C++5.11仍不支持
浮点型
float
double
long double
1. 在Dev C++中,长度依次为:4、8、16 2. 浮点数的长度须满足: long double >= double >= float 3. float有6位有效数字,double有15位有效数字,long double有19位有效数字 4. 浮点数精度会丢失
字符型
char
在C99中,字符型是整型的一种。
char除做1个Byte的整数外,还作为字符型使用。用以存放ASCII码字符,使用时用单引号包含。例如:'a','0'。
注意:0和'0'是不一样的。前者是数字0,后者是字符0,后者也可表示数字48,即'0'的ASCII码值。
空类型(void)
枚举类型(enum)
派生类型
指针类型(*)
char*, int*, void*, ......
数组类型([])
int array[], ......
结构体类型(struct)
共用体类型(union)
函数类型
数据类型的转换
(目标类型名)(表达式)
把表达式的结果强制转换为目标类型
例:(int)(12.3+5) //把12.3+5的结果17.3强制转换为整型,其结果为17 printf("%d",(int)(12.3 + 5)); // 17
常量
在程序运行过程中,不发生改变的量
字面常量/直接常量
整型常量
例:0,-1,100,1000000000L
实型常量
例:12.34, -1.0,1.23e5,-1.3e-3
实型常量在Visual C++被默认为双精度类型,需要用lf输出
字符常量
普通字符
例:'a','A','0','8','*'
转义字符
例:'\n','\\','\t','\?','\060','\x30'
详见教材第40页
字符串常量
例:"abc","abc123"等
符号常量
用#define指令,用一个符号代表一个字面常量
#define PI 3.14159
用PI代表3.14159
规范写法:符号要大写,单词之间用下划线分开,表意清楚
例:#define PRICE_OF_APPLE 3.4
行尾不要加分号
变量
变量代表一个有名字的、具有特定属性的存储单元。
变量名:存储单元的名字
规范:望文知意
变量值:存储单元里面的值
数据类型:存储单元里存放数据的类型
变量地址:存储单元的地址
定义
DataType VariableName[ = InitializedValue];
每行一个变量,行尾加分号
例:int length = 10;
C语言规范要求:变量定义时务必要有初始值。
通常用于定义文件,定义文件的扩展名为:c
声明
DataType VariableName;
每行一个变量
例:int length;
通常用于头文件,头文件的扩展名为:h
常变量
变量的形式、常量的本质。 通常,编译器不为常变量分配存储空间,而是将其存在符号表内,效率较高。
const DataType VariableName = Value;
每行一个常变量,其值不能修改
例:const float pi = 3.142;
const修饰指针
const int *p
p可变,*p不可变
int const *p
p可变,*p不可变
int *const p
p不可变,*p可变
const int *const p
p不可变,*p不可变
运算符
算术运算符:+(加)、 -(减)、 *(乘)、 /(除)、 %(取余)、 ++(自加)、 --(自减)
++、--
前置 表达式的值为操作后的值,操作完成后变量值自加或自减1
后置 表达式的值为操作前的值,操作完成后变量值自加或自减1
不要再复杂场景下使用++、--运算符。避免不必要的阅读困难。
关系运算符:>(大于)、 >=(大于等于)、 <(小于)、 <=(小于等于)、 ==(等于)、 !=(不等于)
逻辑运算符:&&(与)、 ||(或)、 !
短路求值。例:a = 3; printf("%d %d\n",0&&(++a), a);//0 3
赋值运算符:=, +=, -=, *=, /=, %=
变量 赋值运算符 表达式
左值和右值
左值标识一个指定的存储位置
右值提取存储再当前位置的值
位运算符:<<(左移), >>(右移), ~(反), &(与), |(或), ^(异或)
条件运算符:?:
逗号运算符:,
指针运算符:*, &
强制类型转换运算符:()
成员类型操作符:., ->
运算符的优先级与结合性
先乘除后加减,从左往右算。
使用小括号提高运算优先级,在优先级不明显的地方用小括号进行明确。
混合运算,最大限度保留精度。例:整型+浮点型的结果为浮点型。
Scanf
所在库
stdio.h
调用格式
scanf("格式字符串",地址列表)
按照格式,把键盘输入的数据,放到地址列表指定的地址里
格式符要与输出参数一一对应,且类型一致
建议:双引号内,不要使用非格式字符
格式字符串
d/i:输入有符号十进制数
u:输入无符号十进制数
o:输入无符号八进制数
x/X:输入无符号十六进制数
数据项必须由空格、制表符和换行符分割。逗号和分号等不是分隔符。
c:输入单个字符
空格、回车、制表符等都算字符
s:输入字符串,将字符送到字符数组中。以非空白字符开始,以空白字符结束。字符串以串结束标志'\0'作为最后一个字符。
f:输入实数,可以是小数形式,也可以是指数形式
e/E/g/G:与f相同,不区分大小写
ld/lo/lx/lu/lf/le:输入长型数据
hd/ho/hx:输入短型数据
域宽:指定输入数据所占宽度。
*:本输入项在读入后不赋给相应的变量
语句
顺序语句
block
把一条或多条语句用{}括起来,即为block
例1:{ ; }
可以为空语句
例2:{ a += 3; b *= sqrt(a) - 1; }
可以为1条或多条语句
例3:{ if (a > b) { a = 100; } }
也可以为分支语句,循环语句等合法语句
分支语句
if语句
如果满足关系表达式,则执行相应的block,否则均不执行
基本语法
if (关系表达式) block
例:if (0 < delta) { printf("没有实数根\n"); }
if (关系表达式) block1 else block2
例:if (0 < delta) { printf("没有实数根\n"); } else { printf("有实数根\n"); }
if (关系表达式1) block1 else if (关系表达式2) block2 ... else block n
例:if (0 < delta) { printf("没有实数根\n"); } else if (0 == delta) { printf("有且只有一个实数根\n"); } else { printf("有两个不同的实数根\n"); }
switch语句
基本语法
switch(表达式) { case 常量表达式1: 一条或多条语句 break; case 常量表达式2: 一条或多条语句 break; ... case 常量表达式n: 一条或多条语句 break; default: 一条或多条语句 }
例: switch (a) { case 1: printf("Monday"); break; case 2: printf("Tuesday\n"); break; case 3: printf("Wednesday\n"); break; case 4: printf("Thursday\n"); break; case 5: printf("Friday\n"); break; case 6: printf("Saturday\n"); break; case 7: printf("Sunday\n"); break; default: printf("error\n"); }
常量表达式的值,必须为整型。
常量表达式在同一个switch中,必须是唯一的。
规范用法1:每个分支后面的break语句不能省略。
规范用法2:default分支不能省略。如果不需要任何操作,可以放一个空语句。
循环语句
while语句
基本语法
while (条件表达式) block
在条件表达式为真时,block被反复执行,直至1)条件表达式为假,或2)遇到break语句。
例: i = 1; while (i <= 100) { printf("循环第%d次\n",i); i++; }
1. 在while语句之前,需要初始化循环变量 如例中的i = 1; 2. 在block中,需要修改循环变量的语句。 如例中的 i++;
do while语句
基本语法
do block while(关系表达式)
执行block,直至1)条件表达式为假,或2)遇到break语句。
与while的区别是,不管条件是否为真,block都会被执行一遍。
例: i = 1; do { printf("循环第%d次\n",i); i++; } while (i <= 100);
1. 在do while语句之前,需要初始化循环变量 如例中的i = 1; 2. 在block中,需要修改循环变量的语句。 如例中的 i++;
for语句
基本语法
for(初始化循环变量; 条件表达式; 循环变量修改语句) block
例: for(i = 1; i <= 100; i++) { printf("循环第%d次\n",i); }
for语句相比while语句,显得更加简洁
break
跳出本层(一层)循环
continue
终止本次循环,直接进入下次循环判断
数组
数值数组
一维数组
定义
dataType arrayName[常量表达式] = {};
arrayName是地址常量,指向数组的首地址
首地址:首个元素的地址
数组地址和首地址数值上一样,但含义不一样
规定:数组指针(*)[]指向1D数组
dataType (*p)[N] = &arrayName
指针p指向N个元素的1D数组
例: int scores[30] = {0};
数组元素的引用
只能逐个引用 例如:arrayName[1]
数组索引从0开始,至“常量表达式”-1结束,共计“常量表达式”个
不能越界!arrayName[0], ..., arrayName[常量表达式-1]
数组若不初始化,其元素值为随机数。
二维数组
定义
dataType arrayName2D[常量表达式1][常量表达式2] = {};
arrayName2D是地址常量,二维数组的首地址
首地址:首个元素的地址
数组地址和首地址数值上一样,但含义不一样
规定:数组指针(*)[][]指向2D数组
dataType (*p)[M][N] = &arrayName2D
指针p指向M个元素的2D数组
arrayName2D == &arrayName2D[0] == &arrayName2D[0][0] arrayName2D[i] == &arrayName2D[i][0] arrayName2D + i == &arrayName2D[i]
例: int arrayName2D[5][5] = {{0},{0}};
数组元素的引用
只能逐个引用 例如:arrayName[1][1]
使用双重循环来依次输入输出数组
初始化
按行赋值:int x[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
按元素赋值:int x[][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
不能省略第二维长度
部分赋值:int[3][4] = {{1,2},{5,6,7}};
字符数组
字符在C语言中,是单字节的整数类型。所以用法同整型数字数组一样
字符串
字符串的存储是以数组的形式存储的。但有点特殊
特殊之处在于:数组里存的是:字符串+'\0'
1. 数组的长度 >= 字符串长度 + 1
char c[] = {"China"}; 等价于: char c[] = {'C','h','i','n','a','\0'}; 不等价于 char c[] = {'C','h','i','n','a'};
char c[] = {'H','e','l','l','o','\0','C','h','i','n','a','\0'}; printf("%s\n",c); // 输出:Hello for (i = 0; i <= 11; i++) { printf("%c",c[i]); } //输出:Hello China
string.h
puts(字符数组)
gets(字符数组)
strcat(字符数组1,字符数组2)
strcpy(目标字符数组,源字符数组)
strcmp(字符串1,字符串2)
strlen(字符数组)
strlwr(字符串)
strupr(字符串)
数组与指针
预备知识
变量的指针/地址
变量名前加 &
例:
1||| int var = 0; 变量var的地址或指针为:&var
2||| int a1d[10] = {0}; 数组a1d的地址为:&a1d
获得地址/指针中的数据
地址/指针前加 *
例
int var = 123; int *p = &var; int tmp = *p; 获得指针p中的内容123,赋值给tmp
变量
dataType variableName [= initializedValue];
1||| int var = 0;
2||| char c = 'a';
数组
由一组数据类型相同的数据构成的集合。
1||| 数值数组:int num_array[10] = {0};
2||| 字符数组:char char_array[10] = {'a'};
3||| 二维数组:int a2d[3][4] = {{0}};
4||| 指针数组:int *p[4] = {a2d[0],a2d[1],a2d[2],a1d};
5||| ......
一维数组 int a1d[10] = {0};
由一组数据类型相同的变量构成的集合
数组元素:a1d[id]
a1d[id] 用法与 var 完全相同
数组名:a1d
数组首元素的地址,简称首地址。
类型:int *
数组地址
&a1d
类型:int (*)[]
注:数组首地址 ¹ 数组地址。
二维数组 int a2d[3][4] = {{0}};
由一组数据类型相同的一维数组构成的集合
数组元素:a2d[id1][id2]
a2d[id1][id2]用法与 var 完全相同
由一维数组构成
a2d[0]、a2d[1]、a2d[2]的用法与a1d完全一致
数组名:a2d
数组首元素的地址
类型:int (*)[]
二维数组的首元素是一维数组,一维数组地址类型(*)[]
例:int (*p)[10] = a2d;
数组地址
&a2d
类型:int (*)[][]
指针数组 int *p[4] = {a2d[0],a2d[1],a2d[2],a1d};
由一组指针构成的集合
数组元素p[0],p[1],p[2],p[3],其用法和 &var 完全相同
数组名:p
数组首元素的地址
类型:int **
首元素的内容为指针,所以是指针的指针,即双重指针
例:int **p2 = p;
数组地址
&p
类型:int *(*)[];
int *(*p3)[4]=&p;
例:
本文件为C++源文件,不是C语言源文件。 因为C语言没有输出变量类型的方法,此处借用了C++的方法。
#include <stdio.h> #include <typeinfo.h> int main() { int var = 0; int a1d[10] = {1,2,3,4,5,6,7,8,9,0}; int *p_var = &var; int (*p_a1d)[10]= &a1d; printf("\n"); printf("\t&var:\t\t%s\n",typeid(&var).name()); printf("\t&a1d[0]:\t%s\n",typeid(&a1d[0]).name()); printf("\ta1d:\t\t%s\n",typeid(a1d).name()); printf("\t&a1d:\t\t%s\n",typeid(&a1d).name()); printf("\n"); int a2d[3][10] = {{0}}; int (*p1_a2d)[10] = a2d; int (*p_a2d)[3][10] = &a2d; printf("\ta2d:\t\t%s\n",typeid(a2d).name()); printf("\t&a2d[0][0]:\t%s\n",typeid(&a2d[0][0]).name()); printf("\ta2d[0]:\t\t%s\n",typeid(a2d[0]).name()); printf("\t&a2d[0]:\t%s\n",typeid(&a2d[0]).name()); printf("\t&a2d:\t\t%s\n",typeid(&a2d).name()); printf("\n"); int *p[4] = {a2d[0],a2d[1],a2d[2],a1d}; int **p2 = p; int *(*p3)[4]=&p; printf("\tp:\t\t%s\n",typeid(p).name()); printf("\tp[0]:\t\t%s\n",typeid(p[0]).name()); printf("\t&p[0]:\t\t%s\n",typeid(&p[0]).name()); printf("\tp2:\t\t%s\n",typeid(p2).name()); printf("\t&p:\t\t%s\n",typeid(&p).name()); printf("\n"); return 0; }
&var: Pi &a1d[0]: Pi ald: A10_i &ald: PA10_i a2d: A3_A10_i &a2d[0][0]: Pi a2d[0]: A10_i &a2d[0]: PA10_i &a2d: PA3_A10_i p: A4_Pi p[0]: Pi &p[0]: PPi p2: PPi &p: PA4_Pi
i:int P:指针 数字:元素个数 A:数组 规则:后面修饰前面的 例如:PA10_i:包含10个整型元素的数组指针。
数组-函数-指针
函数 Type Name(Arguments_List)
声明
int add(int a, int b);
位置
main函数前面
头文件
定义
int add(int a, int b) { return (a + b); }
调用
int sum = 0; sum = add(3,2);
声明、定义、调用三者要一致
参数传递
实际参数传递给形式参数
单向
值传递
实参、形参的类型要一致
按位置传
返回值
函数类型、返回值类型、调用时的类型要一致
例题
1||| #include <stdio.h> int add(int a, int b); // 函数声明 int main() { int sum = 0; sum = add(3,2); // 函数调用 return 0; } int add(int a, int b) // 函数定义 { return (a + b); }
2|||
#include <stdio.h> int test(int [], int x2[], int *, int *x4,int (*x5)[5]); int main() { int a[5] = {1,2,3,4,5}; int tmp = 0; tmp = test(a,&a[0],a,&a[0],&a); printf("%d\n",tmp); return 0; } int test(int x1[], int x2[], int *x3, int *x4,int (*x5)[5]) { int temp = 0; temp = x1[0] + x2[0] + *x3 + *x4 + (*x5)[0]; return (temp); }