前言
谈到C语言,很多人都会笑笑,好像C语言看起来很平凡,很普通,很大众。然而值得注意的是,这是一门极其底层的语言,可以直接调用汇编语句,使用系统函数。不论是系统开发,驱动开发,操作系统还是缓冲区溢出攻击等,C语言永远是理解万物的基石。
说来惭愧,博主此刻距离C语言的第一堂课已两年有余,虽然还都记得,但在学习时浅尝辄止,甚至使用VC大部分都只是点了一下“!”。那么,就从这里,开始重拾C语言,用C语言进行更多的开发和使用,也用一个信息安全学生的角度重新去审视C语言自己应该注意些什么。祝愿自己在明年夏天找工作前尽快掌握更多底层知识,创造更多有价值的成果。
一些简单的知识,博主不再记录,只做有意义的事。
第一阶段的学习参照《学通C语言的24堂课》,如需图书资源请在下方评论。
第一部分 基础篇
一、数据类型有:
1.基本类型:整型、字符型、实型(浮点型)和枚举类型。
2.构造类型:数组类型、结构体类型和共用体类型。
3.指针类型:C语言的精华所在,指针的值表示某个内存地址。
4.空类型:关键字是void,对函数返回进行限定及对函数参数进行限定。
转义字符:
1.\n:回车换行
2.\t:横向跳到下一制表位置
3.\v:竖向跳格
4.\b:退格
5.\r:回车
6.\f:走纸换页
7.\\:反斜线“\”
8.\a:鸣铃
9.\ddd:1~3位八进制数所代表的字符
10.\xhh:1~2位十六进制数所代表的字符
define定义符号常量
读到了扎克伯格的奋斗史,如果说他对信息的使用触及了底线,我想在他在哈佛大学学习时期,已经有这样的思想了。
二、表达式是C语句的主体,在C中表达式由操作符和操作数组成。表达式产生的作用有以下两种情况:放在赋值语句的右侧、放在函数的参数中。
赋值运算符=
强制类型转换:(类型名)(表达式)
算术运算符:两个单目运算符(正、负)和5个双目运算符(加减乘除和取模)。在算术表达式中,加减乘除和日常数学里的规则一样。应当注意一下,在运算符结合性上,分为自左向右和自右向左两种。同时要注意算术运算符的优先级。
关系运算符。需注意的是==和=的区别。
逻辑运算符&&、||、!。
位逻辑运算符与表达式:
1.位逻辑运算符:&(位逻辑与)、|(位逻辑或)、^(位逻辑异或)、~(取反),值得注意的是这四个运算符只能用于整型表达式。通常用于对整型变量进行位的设置、清零和取反,以及对某些选定的位进行检测。
2.检查位的表达式:if(Field&BITMASK)。其中运算符用来对BITMASK变量的位进行检测,检测是否与Field变量的位有吻合之处。
逗号运算符:
表达式1,表达式2,……,表达式n
逗号表达式的求解过程是:先1,后2,再3,直到最后n。整个表达式的值是表达式n的值。
值得注意的是,a=2+5,3+5,4+5,a的值是7而不是9,这是因为赋值运算符的优先级比逗号运算符的优先级高。可以改为a=(2+5,3+5,4+5),a的值此时为9.
三、数据输入/输出函数
语句是用来向计算机系统发送操作指令的。一个程序包含声明部分和执行部分,执行部分为语句,而定义变量这种声明部分则不是语句。
字符的输入输出 :putchar(ch)用于字符或转义字符的输出,getchar()用于字符的输入
字符串的输入输出:puts(char *str)用于字符串的输出,gets(char *str)用于字符串的输入。这里括号里的事一个字符数组
printf格式输出:
printf的附加格式:
scanf使用的格式字符:
值得注意的是字符串结束标志为‘\0’,常常用于缓冲区溢出的使用。
scanf的附加格式:
四、设计选择/分支结构程序
if语句、if……else语句、else if语句
条件运算符
switch语句,最最关键的default,用于对自己还未想到的情况统一处理,忽略了它是很多漏洞出现的原因,无论是c、java、python,还是各种网络脚本语言。上面的else也有此类作用。
谈及if else和switch的比较,前者速度更快,但在处理五种以上的多种情况时,显然在代码编辑和结构上不如switch。
五、循环控制
while语句
do……while语句
for语句,一般形式为for(表达式1,表达式2,表达式3)。我们更多关注它的变体:
如果省略了表达式1,则应在for语句之前就进行赋值;
省略表达式2,则会无限制的循环,设计一下可吃掉内存;
省略表达式3,也会无终止的循环,吃掉内存。
使用逗号表达式,则会在执行相应语句的时候,从左到右执行。
比较一下:
循环嵌套
转移语句:
goto语句,无条件转向语句,可以使程序立即跳转到函数内部的任意一条可执行与。goto关键字后面带一个标识符,这个标识符是同一个函数内某条语句的标号。
如:
//
// main.cpp
// cd练习
//
// Created by 张立鹏 on 2018/12/22.
// Copyright © 2018年 张立鹏. All rights reserved.
//
#include <iostream>
int main(int argc, const char * argv[]) {
// insert code here...
goto Show;
printf("The message before ShowMessage");
Show:
printf("ShowMessage\n");
return 0;
}
上述函数中,第一个printf没有得到执行,执行结果为:
break语句,可用于退出循环
continue语句,用于结束本次循环,进入下一次的循环操作。
六、数组
数组需要注意下标为0~n-1,事实上指针数组超过了n-1后,就出现了溢出现象。
一维数组
二维数组
多维数组
数组排序方法:选择、冒泡、二分、插入、交换。
要注意数组元素之间的比对,=和equal之间有很大差别,前者是变量地址,后者是数组元素包含的值。
七、字符数组
字符数组的结束标志为\0,因此字符数组等于“HELLO”时,实际上有六个元素,因为还有一个“\0”。
字符串处理函数:
字符串复制:strcpy(目的字符数组名,源字符数组名)。可以从字符串或者字符数组复制到字符数组里面,目的字符数组不可是字符串。当然了,更不允许使用一个系统定义的赋值语句讲一个字符串常量或字符数组直接付给一个字符数组。
字符串连接:strcat(目的字符数组名,源字符数组名)。
字符串比较:strcmp(目的字符数组名,源字符数组名)。
字符串的大小写转换。
获取字符串长度。
第二部分 提高篇
一、函数的应用
二、变量的存储类别
三、指针
指针的自加,是进入下一个字节,可以说p++即为p=p+4
也可以定义指针数组,而在二维数组和指针的结合中:
使用字符指针执行一个字符串,即理论上将字符串看作一个字符数组,使用指针和数组的结合来访问字符串。字符串数组和字符的结合使用,则把字符串数组成功变成了二维数组来处理。这样都是可行的,只是务必要注意\0这一字符串结尾字符。
指向指针的指针
指针变量作为函数参数,需要注意的是指针作为形参,会真正对指向的变量进行操作,而普通变量只是调用,函数完毕后,仍未原值。指针变量做函数参数调用函数虽然不能改变实参指针变量的值,但可改变实参指针变量所指变量的值。
返回指针值的函数,可能并不能简便易行,这里只是说明其真实存在:
#include <iostream>
int *per(int a,int b);
int Perimeter;
int main(){
int iWidth,iLength;
int *iResult;
printf("请输入长方形的长:\n");
scanf("%d",&iLength);
printf("请输入长方形的宽:\n");
scanf("%d",&iWidth);
iResult=per(iWidth, iLength);
printf("长方形的周长是:\n");
printf("%d\n",*iResult);
}
int *per(int a,int b){
int *p;
p=&Perimeter;
Perimeter=(a+b)*2;
return p;
}
结果:
请输入长方形的长:
6
请输入长方形的宽:
4
长方形的周长是:
20
Program ended with exit code: 0
指针数组作main函数的参数
带参的main()函数形式为:main(int argc,char *argv[])。从形式上看,包括一个整型和一个指针数组。
四、结构体
将结构体变量换成数组,就形成了结构体数组,
结构体指针的使用:
//
// main.cpp
// Created by 张立鹏 on 2018/12/22.
// Copyright © 2018年 张立鹏. All rights reserved.
//
#include <stdio.h>
#include <string.h>
struct Student{
char cName[20];
int iNumber;
char cSex;
int iGrade;
}student;
int main(){
struct Student* pStudent;
pStudent=&student;
strcpy(pStudent->cName, "SuYuQun");
pStudent->iNumber=1017;
pStudent->cSex='M';
pStudent->iGrade=3;
printf("--The Student's information---\n");
printf("Name:%s\n",student.cName);
printf("Number:%d\n",student.iNumber);
printf("Sex:%c\n",student.cSex);
printf("Name:%d\n",student.iGrade);
return 0;
}
指向结构体数组的指针:
//
// main.cpp
// Created by 张立鹏 on 2018/12/22.
// Copyright © 2018年 张立鹏. All rights reserved.
//
#include <stdio.h>
#include <string.h>
struct Student{
char cName[20];
int iNumber;
char cSex;
int iGrade;
}student[5]={
{"WittPeng1",001,'M',3},
{"WittPeng2",002,'W',3},
{"WittPeng3",003,'M',2},
{"WittPeng4",004,'M',3},
{"WittPeng5",005,'W',3}
};
int main(){
struct Student* pStudent;
int index;
pStudent=student;
for(index=0;index<5;index++,pStudent++){
printf("No.%d student:\n",index+1);
printf("Name:%s\n",pStudent->cName);
printf("Number:%d\n",pStudent->iNumber);
printf("Sex:%c\n",pStudent->cSex);
printf("Name:%d\n",pStudent->iGrade);
}
return 0;
}
结构体可做函数参数。
包含结构体的结构体。
五、共用体
共用体看起来很像结构体,但结构体定义了一个由多个数据成员组成的特殊类型,而共用体定义了一块为所有数据成员共享的内存。共用体也称联合,使几种不同类型的变量放在同一段内存单元中,共用体在同一时刻只能有一个值,属于某一个数据成员。由于所有成员处于同一块内存,因此共用体的大小就等于最大成员的大小。
//
// main.cpp
// Created by 张立鹏 on 2018/12/22.
// Copyright © 2018年 张立鹏. All rights reserved.
//
#include <stdio.h>
enum Color{Red=1,Blue,Green} color;
int main(){
int iColor;
scanf("%d",&iColor);
switch (iColor) {
case Red:
printf("The color is Red\n");
break;
case Blue:
printf("The color is blue\n");
break;
case Green:
printf("The color is green\n");
break;
default:
printf("???\n");
break;
}
return 0;
}
六、预处理命令
宏定义
带参的宏定义:
例:
#include指令
条件编译:只对其中某一部分内容满足一定条件的时候才会进行编译。
#if命令,一般形式为:
#if 常数表达式
语句段
#endif
如果常数表达式为真,则编译语句段,否则跳过这段程序。
#else语句
#elif语句
三、高级篇
一、存储管理
内存组织方式:程序被组成4个逻辑段,可执行代码、讲台数据、动态数据(堆)、栈。
在堆的管理中,malloc函数和free函数来从堆中动态地分配和释放内存。
calloc函数,原型为void * calloc(unsignned n,unsigned size),在内存中动态分配n个长度为size的连续内存空间数组。calloc函数会返回一个指针,该指指向动态分配的连续内存空间地址。当分配错误时,返回NULL。
例如使用该函数分配一个整型数组内存空间,代码为:
int* pArray;
pArray=(int*)calloc(3,sizeof(int));
realloc函数
free函数:
内存丢失
二、链表在C语言中的应用
数据结构的知识了。链表相对于数组,插入和删除很方便,但是查询环节很麻烦。
三、栈和队列
栈为先进后出,队列为先进先出。
四、C语言中的位运算
一个字节由8位二进制组成。
位运算操作符:
循环移位:
位段:
位段类型是一种特殊的结构类型,其所有成员均以二进制位为单位定义长度,并称结构中的成员为位段。
关于位段需要分配多少位,要看这一位对应的情况有多少,和信息位与情况种类的原理相同。
五、文件操作技术
文件的打开:
文件的关闭:
fclose(文件指针)
文件的读写:
文件的定位:
六、图形图像处理
getche用于从键盘上获取一个字符。
图形显示
图形模式下的文本输出
(此部分博主没有展示,需要相关资料的请于下方评论)
谢谢阅读~