C语言初级
标签(空格分隔): c 学习笔记
一、 知识准备
1.头文件:工具箱
#include <stdio.h>
#include "stdio.h"
- <>与""区别:搜索路径不同
- <>:直接在系统目录进行查找,找不到会报错
- “”:先在当前目录下查找,找不到再在系统目录进行查找,还找不到会报错
xxx.c —源文件
xxx.h —头文件
2.vs项目改为控制台显示
项目右键->属性->
3.快捷键
- 调试运行:ctrl+f5 或 fn+ctrl+f5
- 调试快捷键(林耀14):ctrl+fn+f10
- 调试语句(逐条):ctrl+fn+f11
4.ASCII表
5.静态库
静态库的生成与使用(47 35:00后)
导入静态库
#program comment(lib,"sub.lib")
6.内存分区
栈区使用习惯:先使用高地址,再使用低地址
若i在栈中处于高地址,且arr[12]刚好指到i所在栈的地址,就会在循环中将arr[12]置为0,即将i置为0,会使循环进入死循环
二、基本数据类型
1.数据类型
常量:整型常量 实型常量 符号常量 地址常量 字符常量 字符串常量
整型常量:0xa1 0XA1(0x用小写后面数值就用小写…)
实型常量:6.123e3=6.123E3=6.12310的3次方
8.2e-10=8.210的-3次方
符号常量:用一个标识符来表示一个常量
#define PI 3.14
地址常量:内存编号,不可改变
字符常量:''包裹的一个字符
‘1’表示字符1(非数字1)
\为转义字符,如’\'表示\ '\d’表示换行 '\255’表示ascii码255所表示的字符
字符串常量:""包裹的一串字符(可以只有1个,实际上每个字符串后都有\0作为结束标志,只是我们看不到)
合法标识符:由数字、字母、下划线组成;开头不能是数字(一般不把下划线放开头,系统常这样使用,会混淆);不能是关键字
注意事项:c语言(命名)区分大小写
基本数据类型:
整型 short(2字节) int(2/4字节) long(4字节)long long(8字节)
实型 float(4byte) double(8byte)
字符型 char(1byte)
枚举型 enum
- sizeof():计算类型或变量所占空间大小,是求字节数(1字节8位)
- c语言标准:sizeof(long)>=sizeof(int)
- 有符号的(signed) 无符号的(unsigend)
- 小数默认是double类型 3.14(double类型)3.14f(float类型)(精确的不同)
- 单位
bit - 比特位(一个二进制单位)
byte - 字节=8bit
类型 | 有符号 | 无符号 |
---|---|---|
short | -32767—32768 | 0—65535 |
char | -127–128 | 0–255 |
整数之间进行运算,结果还是整数;如5/2=2
2.分类
1.变量
-
局部变量:{}内部定义的
-
全局变量:{}外部定义的
当局部变量和全局变量名字冲突时,局部优先
2.常量
- 字面常量:示例如下
3.14;
10;
'a';
"asd";
- const修饰的常变量:const修饰的变量(num)-具有常属性(不能被改变的属性),本质还是变量
const int num=20;
num=20;//此行会报错
- define定义的标识符常量:不可修改
#define MAX 1000
main(){
int n=MAX;
printf("%d\n",n);
}
- 枚举常量:可以一一列举的常量
enum Sex{
//这种枚举类型的变量的未来可能取值
//枚举常量(值默认从0开始)
MALE;
FEMALE;
}
main(){
enum Sex s=MALE;
printf("%d\n",MALE);//结果为0
printf("%d\n",FEMALE);//结果为1
}
3.输入输出
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int a,b;
char arr[20]={0};
scanf("%d %d",&a,&b);//输入
scanf("%s",arr);//arr本就是地址
printf("a=%d,b=%d\n",a,b);//输出 \n换行
使用scanf()时会报
'scanf': This function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
的错误;解决方法,在代码第一行添加
#define _CRT_SECURE_NO_WARNINGS 1
或者使用scanf_s函数(vs编译提供的,与scanf使用有区别,非c语言标准规定的)
全局添加:在vs安装目录下的newc++file.cpp文件中添加#define _CRT_SECURE_NO_WARNINGS 1 后,即可实现新建.c文件时自动添加这段代码
4.作用域和生命周期
局部变量作用域:就是变量所在的局部范围
全局变量作用域:整个工程(跨文件时要声明后才能使用)
//test1.c文件
//全局变量
int g_val=10;
//test2.c文件
//声明一下变量
extern int g_val;
int main(){
printf("%d\n",g_val);
return 0;
}
局部变量生命周期:进入局部范围生命开始,出局部范围生命结束
全局变量生命周期:整个程序的生命周期
5.字符串和转义字符
1.字符串:就是一串字符——用双引号括起来的一串字符
字符数组:数组是一组相同类型的元素
char arr1[]="hello";
cahr arr2[]={'h','e','l','l','\0'};//与上面相同
int len=strlen(arr1);//为5
字符串结束标志是一个\0的转义字符,计算长度是不计算结束标志
2.转义字符
\\表示输出\
\n表示换行
\ddd:ddd表示1~3个八进制数字,如\130=X 八进制130是十进制的88,而X的ASCII码值是88
\xdd:dd表示两个十六进制数,如\x30=0 十六进30是十进制的48,而0的ASCII码值是48
6.格式符
格式符 | 说明 |
---|---|
%d和%i | 带符号十进制形式输出整数的(正数输出+) |
%o | 八进制无符号输出整数 |
%x | 十六进制无符号输出整数,小写的x是输出小写的a-f,大写X得到 A-F |
%u | 无符号形式输出整数 |
%c | 只能输出一个字符 |
%s | 输出字符串 |
%f | 小数形式输出单双精度,隐含输出6位小数 |
%p | 按地址格式打印——十六进制的打印 |
%e | 以指数形式输出实数,这个%e和%E也是输出的时候e的大小写区别 |
%g | %f和%e格式中输出宽度较短的一种格式,不输出无意义的0 |
三、操作符和表达式
1.算术操作符(7个)
+ - * / % ++ --
%:前后必须为整数
自增/自减
++/–:前置,先算后用;后置,先用后算
- 前置优先级低
- 前置运算效率高
int num=12;
printf("%d,%d",++num ,num++);//结果为14,12 这个与编译器的实现有关,研究没意义
2.关系操作符
< > >= <= == !=
- 比较两个字符串是否相等不能使用==
3.逻辑操作符
与(&&):同真为真
或(||):有真为真
非(!):取反(单目操作符)
- 非0为真,一般用0表示真,1表示假
- 表达式1&&表达式2:当表达式1为假时,表达式2就不用算了,因为结果比为假
- 表达式1||表达式2:当表达式1为真时,表达式2就不用算了,因为结果比为真
4.条件操作符
条件?操作一:操作二
条件为真执行操作一,条件为假执行操作二
5.位/位移操作符
- 按二进制进行运算
- 使用二进制补码进行运算
- 原码->反码:符号位不变,按位取反
- 反码->补码:反码加1
- 补码->原码:符号位不变,按位取反,再加1
- 正整数的原,反,补码一样
- 整数在内存中存储的是补码
按位与(&):同1为1
按位或(|):有1为1
按位非(~):按位取反(包括符号位)
按位异或(^):相同为0,不同为1
左移(<<):向左移动,低位补0
右移(>>):向右移动,高位补符号位(算术右移)/补0(逻辑右移)
- 按位与,或,异或 操作数必须为整数
int a=10;
int b=a>>1;//结果a=10,不变,b=5
1.计算:3&5=1 3原/反/补码: 0000 0011 5原/反/补码: 0000 0101 按位与(补码):000 0001
结果(原码):0000 0001=1
2.计算:-3&5=5
-3原码:1000 0000 0000 0000 0000 0000 0000 0011
-3反码:1111 1111 1111 1111 1111 1111 1111 1100
-3补码:1111 1111 1111 1111 1111 1111 1111 1101
5原/反/补码: 0000 0000 0000 0000 0000 0000 0000 0101
按位与:0000 0000 0000 0000 0000 0000 0000 0101(符号位为0,是正数,补码与反码、原码一致)
结果(原码):0000 0000 0000 0000 0000 0000 0000 0101=5
交换两个int变量,不使用第三个变量
法一:(问题:数值太大会溢出)
int a=2,b=3;
a=a+b;
b=a-b;
a=a-b;
法二:
int a=2,b=3;
a=a^b;
b=a^b;
a=a^b;
6.逗号表达式
起链接作用
第一部分,第二部分,...,第n部分
int a=0,b=3,c=5;
int d=(a=b+2,c=a-4,b=c+2);//结果d为3
最终取值:依次运算,取第n部分的值
7.指针运算符
1.取内容(*):解引用(间接引用)操作符
2.取地址(&):取地址(%p打印)
int a=10;
printf("%p\n",&a);
int * pa=&a;//*是用来告诉我们pa是指针变量
*pa=20;//*是解引用操作符,这句的意思是把20赋值给a
printf("%d\n",a);//结果输出为20
指针类型会变,但传递的参数是地址,地址数据所占字节大小不变
3.下标引用操作符([]):(如数组下标 arr[4])[]的操作数是2个:arr和4
8.求字节运算符,其他运算符
sizeof():求字节运算符,计算类型或变量的大小 sizeof(int) sizeof(a)
- printf(“%d\n”, sizeof(a);//这样写也对,这说明sizeof是操作符而非函数
- sizeof括号中放的表达式是不参与运算的(p71->29min)
int arr[10]={0};
sizeof(arr);//40 10个数,每个数4字节
sizeof(arr[0]);//4
int size=sizeof(arr)/sizeof(arr[0]);
():强制转换类型 int n=(int)3.14;
/函数调用操作符(调用函数,在函数名后有())
作用域符(::):范围包含
结构成员访问操作符(->或.)
//创建一个自定义类型
struct Book{
//结构体的成员(变量)
char name[20];
int id[20];
int price;
};
main(){
int num=20;
struct Book b={"C语言","C20230317",55};
printf("书名:%s\n",b.name);
struct Book* pb=&b;
printf("书号:%s\n",(*pb).id);
printf("定价:%d\n",pb->price);
}
9.优先级
上到下,左到右 优先级降低
10.整形提升
11.算术转换
若操作符的各个操作数属于不同类型,要进行算术转换
向字节长的转换,长度一样,向精度高的转换
12.常见关键字
auto:自动的,每个局部变量都是 auto修饰的
extern:用来申明外部符号的
register:寄存器关键字
register int num=100;//建议num的值存放在寄存器中,提升效率
- 计算机中数据可存储位置
寄存器——更小
高速缓存——几十MB
内存——8G-10G
硬盘——500G
网盘——2T
(由下往上造价越高,速度越快,空间越小)
signed:有符号的
unsigned:无符号的
static:静态的
- static修饰局部变量
改变了局部变量的生命周期(本质上是改变了变量的存储类型)
void test(){
static int a=1;//不使用static修饰,输出10个2,使用static修饰输出2-11
a++;
printf("%d",a);
}
main(){
for(int i=0;i<10;i++){
test();
}
}
- static修饰全局变量
- 使得这个全局变量只能在自己所在的源文件(.c)内部可以使用,其他源文件不能使用
- 全局变量在其他源文件内部可以被使用,是因为全局变量具有外部链接属性,但是被static修饰后,就变成了内部链接属性,其他源文件就不能链接到这个静态的全局变量了
//文件add.c
static int g_val=2022;
//文件test.c
//声明
extern int g_val;
mian(){
printf("%d",g_val);//在add.c中g_val使用static进行了修饰,所以在此处无法使用
}
- static修饰函数
- 使得函数只能在自己所在的源文件(.c)内部可以使用,不能在其他源文件内部使用
- 本质上是将函数的外部链接属性变成了内部链接属性(和static修饰全局变量一样)
//文件add.c
static int ADD(int x,int y){
return x+y;
}
//文件test.c
//声明函数
extern int ADD(int x,int y);
mian(){
int sum=ADD(10,20);//static修饰函数ADD()后,在此处就无法使用了
printf("%d",sum);
}
union:联合体(共用体)
volatile:c语言中暂时不讲(可以体现c语言段位)
typedef:类型重定义
typedef unsigned int u_int;
main(){
typedef unsigned int num=100;
u_int num2=100;//与上一行同样意思
}
const:修饰变量,这个变量就被称为常变量,不能被修改,但本质上还是变量
const int num=10;
int n=100;
int* p1=#
*p1=20;//这里可以通过指针修改num的值
const int* p2=#
//const修饰指针变量的时候
//const如果放在*的左边,修饰的是*p,表示指针指向的内容,是不能通过指针来改变的;但是指针变量本身是可以修改的
*p2=30;//这里就无法通过指针修改num的值
p2=&n;//这里是可以的
//const如果放在*的右边,修饰的是指针变量p,表示指针变量不能被改变但是指针指针的内容,可以被改变
int* const p3=#
*p3=30;//可执行
p3=&n;//不可执行
break case char
continue default do
double else enum
float for goto if int long
return short
sizeof struct switch typedef union void while
- define,include不是关键字,是预处理指令
- define定义常量
#define MAX 10000
- define定义宏:
#define ADD(X,Y) X+Y
#define ADD2(X,Y) ((X)+(Y))
main(){
printf("%d",ADD(2,3));//输出5
printf("%d",4*ADD(2,3));//输出11,非20;因为是4*2+3=11,宏ADD实现了替换
printf("%d",4*ADD2(2,3));//此时输出为20
}
四、控制语句
1.选择语句(if)
1.if/else语句
判断时若有类似if(value10)时可以写成if(10value),因为若判断条件写成value=10,在执行时第一种不会报错,可以正常执行,但结果会出错,且不易找出错误位置;但使用第二种写法,则无法执行,不易出现不好找的导致错误的地方
2.switch语句
default:所以case不匹配时执行
default于case在写代码时无书写顺序的要求
- break:跳出所在循环语句
2.循环语句(while,for,do…while)
1.while循环
- break:在while循环中,用于永久终止循环
- continue:在while循环中,作用时跳过本次循环中continue后面的代码,直接进入判断部分,看是否进行下一次循环
scanf于getchar同时使用,发现结果不对,原因是scanf获取了输入的123456,getchar直接获取了缓冲区的\n,所以没有等到我们区确认,就直接显示了确认结果
解决法一:在getchar前再写一个getchar,用以清除缓冲区,结果输入“ABC 123”时还是有问题,因为scanf获取的是ABC,第一个getchar获取的是空格 ,如图
法二:使用循环清除所以缓冲区
2.for循环
- 判断部分的省略——判断部分恒为真
3.do-while循环
循环体至少执行一次
五、函数
1.是什么
是子函数
分类:库函数,自定义函数
2.库函数
都集成在头文件中,所以使用库函数前都要引用头文件
c++库函数
MSDN
C/C++官网(中文)
C/C++官网(英文)
3.自定义函数
4.参数
改变传递的参数的值
实参与形参
实参:可以是常量、变量、表达式、函数等
形参:只在函数中有效,函数调用完成后就自动销毁
形参实例化后相当于实参的一份临时拷贝
exec((v1,v2),(v3,v4),v5,v6);//逗号表达式
exec(v2,v4,v5,v6);//与上面相等
5.调用
传值调用、传址调用
6.嵌套调用和链式访问
1、嵌套调用
void test3(){
}
int test2(){
test3();
return 0;
}
mian(){
test2();
}
2、链式访问
把一个函数的返回值作为另外一个函数的参数
7.声明和定义
1、函数的定义必须放在main函数之前
若在main后定义,在使用前必须声明
声明时使用 int Add(int x,int y);也可以
2、函数的声明一般放在头文件中
//add.c 源文件
int Add(int a,int b){
return a+b;
}
//add.h 头文件
int Add(int x,int y);
//text.c 源文件
#include "add.h"//声明
main(){
int a=10,b=20;
int c=Add(a,b);//使用
}
8.递归
1.打印每位数字(1352->1 3 5 2)递归方式
2.递归的两个必要条件
- 限制条件,当满足这个限制条件时,递归便不再继续
- 每次递归调用之后越来越接近限制条件的条件
2.Stack Overflow(栈溢出问题)
内存分区:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lvJVbfNL-1680250423338)(null)]
栈区空间被用光,会出现栈溢出问题
写递归代码的时候:
- 1.不能死递归,都有跳出条件,每次递归逼近跳出条件
- 2.递归层次不能太深
汉诺塔代码
自己看看如何实现
六、数组
1.一维创建和初始化
1.创建
int arr[8];
char str[5];
- []内应放常量表达式,而不能是变量
- int arr[n];这样写不行(c99语法有变长数组,会支持这种写法,其他不行)
- 变长数组——数组大小是变量
2.初始化——创建的同时给赋值
int arr1[5]={1,2,3,4,5};//完全初始化
int arr2[5]={1,2,3};//不完全初始化,其他位补0
int arr3[]={1,2,3,4,5};//[]未指定大小,会根据内容默认数组大小未5,等同于arr1
字符数组
char ch1[5]={'b','i','t'};//其他位补0
cahr ch2[]={'b','i','t'};//默认长度为3
char ch3[5]="bit";//b i t \0 0
char ch4[]="bit";//b i t \0
//ch2——[b i t],用printf输出为:bit+乱码;求长度结果ch4也不同,此处为随机值,但数组长度是一定的,为3
//ch4——[b i t \0],用printf输出为:bit;求长度结果为3
2.一维使用
3.一维在内存中的存储
- 数组名是数组首元素的地址
但有2个例外
1.sizeof(数组名)——数组名表示整个数组——计算的是整个数组的大小,单位是字节
2.&数组名——数组名表示整个数组——取出的是整个数组的地址
int arr[]={0}; print("%p\n", &arr);//arr取出的是数组的地址 print("%p\n", &arr+1);//与上面地址差40 print("%p\n", arr);//arr取数组首元素的地址 print("%p\n", arr);//与上面地址差4 print("%p\n", &arr[0]);
- 一维数组在内存中是连续存放的
- 随着数组下标的增长,地址是由低到高变化的
int arr[10]={1,2,3,4,5,6,7,8,9,10};
int * p=arr;
int i=0;
for(i=0;i<10;i++){
printf("%d",*p);
p++;
}
- p是int类型,所以p加一地址会直接加4byte;若p是char类型,则p加一地址加1字节
4.二维创建和初始化
初始化
int arr[3][21]={1,2,3,4,5,6,7,8,9,10,11,12};
第1行:1 2 3 4
第2行:5 6 7 8
第3行:9 10 11 12
int arr[3][22]={1,2,3,4,5,6,7};//不完全初始化——后面补0
第1行:1 2 3 4
第2行:5 6 7 0
第3行:0 0 0 0
int arr[3][23]={{1,2},{3,4},{5,6}};
第1行:1 2 0 0
第2行:3 4 0 0
第3行:5 6 0 0
int arr[][24]={{1,2},{3,4},{5,6}};//行可省略,列不行
5.二维使用
6.二维在内存中的存储
- 二维数组在内存中也是连续存放的
- 一行内部连续,跨行也是连续的
7.作为函数参数
void AA(int arr[]){
//在此处无法使用arr求数组data的大小(sizeof),因为此处arr本质是一个指针,数组大小应该在调用AA之前求,并将求出的值作为参数给AA
}
main(){
int data[]={9,8,7,6,5,4,3,2,1,0};
AA(data);
}
8.实例1:三子棋
9.实例2:扫雷游戏
七、指针
1.是什么
1.内存
1.内存是怎么编号的?
32位->32根地址线->物理线->1/0
64位->…
电信号转换成数组信号:1和0组成的二进制序列
2^32=2的32次方个地址
2.一个这样的内存单元是多大空间?
2的32次方的内存单元
假设:一个内存单元1bit
2的32次方bit=4294967296bit=536870926912Byte=524288KB=512MB=0.5GB
最终一个内存单元是1bite,然后分配地址的(char是1byte)
2.指针变量
1.指针就是地址
- %p专门用来打印地址
printf("%p",&num);
- *也可以是解引用操作
int a=10;
int *pa=&a;//pa是用来存放地址的,在C语言中pa叫指针变量
//* 说明pa是指针变量
//int 说明pa执行的对象是int类型
*pa=20;//修改a的值
//* 解引用操作
//*pa就是通过pa里边的地址,找到a
char ch='w';
char * pc=&ch;
2.指针的大小
sizeof(char *);
指针的大小是相同的(4/8byte)
指针需要多大空间,取决于地址的存储需要多大空间
32位平台——32bit——4byte
64位平台——64bit——8byte
指针定义
其中b不是指针
INT_PTR:是完全替换
但 int* a,b;
中只有a是指针,b不是,若要定义两个指针:int *a,*b;
int_ptr:是int* 的别名(typedef类型重定义)
2.指针和指针类型
指针类型不同,但使用sizeof获取的大小却一样
int * pa;
char * pb;
printf("%d %d\n",sizeof(pa),sizeof(pb));//结果为:4 4
指针类型的意义
1.指针类型决定了:指针解引用的权限有多大(p79——25min)
2.指针类型决定了:指针走一步,能走多远(步长)(p79——29min)
3.野指针
野指针:指针指向的位置是不可知的(随机的、步正确的、没有明确限制的)
1.成因
1.指针未初始化
//这里p就是一个野指针
int *p;//p是局部变量,局部变量步初始化,默认是随机值
*p=20;//非法访问内存了
2.指针越界访问
int arr[10]={0};
int *p=arr;
for(int i=0;i<=10;i++){
*p=1;//会访问到arr[10](第11个值),越界
p++;
}
3.指针指向的空间释放
2.避免野指针
1.指针要初始化
//当前不知道p应该初始化为什么地址的时候,直接初始化为NULL
int* p=NULL;
//明确知道初始化的值
int a=10;
int* ptr=&a;
2.小心指针越界
C语言本身是不会检查数据的越界行为的
3.指针指向空间释放后即时置NULL
4.指针使用之前检查有效性
int* p=NULL;
*p=10;//这样使用会出错
正确使用
int* p=NULL;
if(p!=NULL)
*p=10;
4.指针运算
1.指针±整数
#define N_VALUE 5
float values[N_VALUE];
float* vp;
//values初始化为0
for(vp=&values[0];&vp<values[N_VALUE];){
*vp++=0;
}
int arr[10]=(1,2,3,4,5,6,7,8,9,10 };
int*p= arr;
int* pend = arr + 9;//指向数组最后一个元素
//打印所以数组
while (p<=pend){
printf("%d\n",*p);
p++;
}
2.指针-指针
得到两个指针间的元素个数
- 相减前提:两个指针指向同一块空间
3.指针的关系运算
实际在绝大部分的编译器上是可以顺利完成任务的,然而我们还是应该避免第二种写法,因为标准并不保证它可行。
- 标准规定:
- 允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。
5.指针和数组
int arr[10]=(1,2,3,4,5,6,7,8,9,10]:
int* p= arr;//数组名
printf("%d\n", arr[2]);
printf("%d\n",p[2]);//p[2] -->*(p+2)
6.二级指针
int a=10;
int* pa = &a;//pa是指针变量,一级指针
//ppa就是一个二级指针变量
int **ppa =&pa;//pa也是个变量,&pa取出pa在内存中起始地址
//*ppa==pa
//*pa==a
//=>**ppa==a
7.指针数组——数组
存放指针的数组
int* parr[5];//整形指针的数组
八、结构体
结构体可以让c语言创建新的类型出来
是一些值的集合,但是值的类型可以不同
(数组是一组相同类型的元素的集合)
1.声明与初始化
//创建一个书的类型
struct Book{
char name[20];
};
//创建一个学生类型
struct Stu{
char name[20];//成员变量
int age;
double score;
struct Book book;
}s1,s2;//s1,s2也是结构体变量,是全局变量
main(){
struct Stu s={"张三",20,85.5,{"c语言程序设计"}}//结构体的创建和初始化
//s是结构体对象;是局部变量
printf("1:%s %d %lf %s\n",s.name,s.age,s.score,s.book.name);
struct Stu * ps=&s;
printf("2:%s %d %lf %s\n",(*ps).name,(*ps).age,(*ps).score,(*ps).book.name);
printf("3:%s %d %lf %s\n",ps->name,ps->age,ps->score,ps->book.name);
}
2.成员访问,传参
print1会出现内存空间浪费(要开辟临时空间接收参数)和耗时(参数过大,调用耗时)的问题,所以使用传址调用更好一些,且传址掉用可以修改结构体内容
函数调用的参数压栈:
九、实用调用技巧
1.debug与release的介绍
Debug版本 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序。
Release版本 称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好地使用。
2.Windows环境调试介绍(p85——40min)
ctrl+shift+/:注释
调用堆栈:显示函数调用逻辑
4.如何写出好(易于调试)的代码
5.编程常见错误
《C陷阱和缺陷》
《明解C语言》初级->进阶
《C和指针》
《C语言深度解析》
十、一些常用函数
- sizeof():求字节运算符,计算类型或变量的大小
- getchar():获取一个字符(按ctrl+z就读取结束)
- putchar():输出一个字符
- EOF:end of file——文件结束标志(值为-1)
- strlen:求字符串长度
- Sleep(1000):睡眠1秒(#include<windows.h>)
- system(“cls”):清空屏幕
- strcmp():比较两个字符串,相等返货0;不等返回正数;使用==比较时,比较的是字符串地址,非内容
- srand(int)+rand():获取随机数c视频链接–37
- assert(表达式):断言(表达式为真则没事,为假则程序报错)易于调试,找出bug(头文件:#include<assert.h>)