visual studio 2019调试快捷命令
F9:增加或取消断点
F5:开始执行程序,直到第一个断点处停下
F10:从当前停止的代码行开始,逐行执行
ALT+6:打开内存页面,可查看内存存储的值;查看某变量的地址和存储值。内存页面的编辑框,数组输入数组名,数值型变量输入 &变量名。
小技巧
1.忽略某些报错码,例如报错:error C4996: 'fopen' This function or variable may be unsafe
在源程序文件头 添加:#pragma warning(disable:4996)
数组
初始化:
1.定义数组不给初值,数组内部元素的默认值是随机值;例如:int a[10];
2.定义int数组部分给初值,数组其他元素默认赋值0;例如int a[10]={1,2,3};
3.字符串数组,转义字符'\0'的ASCII码是0,等价于数字0;例如c[10]=0 等价于c[10] = '\0';
4.C语言对字符串常量会自动在字符末尾加一个'\0'作为结束符,所以char a[]="i am happy"是11位长度。但printf("%s\n",a)输出结果不包含'\n';
5.字符数组不会默认末尾添加'\0',char a[] ={'i','','a','m','','h','a','p','p','y'}是10位长度。 为确定字符串的实际长度,一般人为添加'\0',防止输出printf("%s\n",c)出现超过10位的脏数据。
6.char a[120]= "str1";strlen(a)是字符串的实际长度4,sizeof(a)是字符串定义大小120;
函数
1.定义全局变量时只允许在本源程序文件中使用,加static关键字。static int g_a =6;
2.全局变量在定义时分配内存,声明不会分配内存。extern int g_a外部声明不会分配内存;
编译预处理
不带参数的宏定义:
1.用法:#define 宏名 被替换的内容 , 行末不加分号,否则连分号一起替换。
#define PI 3.14; ftmp = PT * 2; 相当于 3.14; * 2 报语法错误。
2.有效范围:#define之后到本源程序文件结束,不能跨文件使用。
带参数的宏定义:
1.用法:#define 宏名(参数表) 被替换的内容
2.被替换内容尽量加上括号,例如 #define s(r) 3.14*r*r,不加括号,这样s(1+5)在替换展开后变成3.14 * 1+5 * 1+5;正确写法:#define s(r) 3.14*(r)*(r)
3.宏展开是在编译阶段进行,仅内容替换不求值(例如1+5),不分配内存。
*************************************************************************************
文件包含:
1.用法:#include "文件名";
2.#include ""和#include <>的区别:<>是去系统目录中找所包含的文件(stdio.h)、""是去当前目录查找,找不到再去系统目录查找。
*************************************************************************************
条件编译:
1.背景:生成可执行文件的过程中,希望源程序文件的部分内容只有在满足一定的条件下才进行编译;
2.形式:
2.1 当标识符被#difine定义过,则对程序段1进行编译,否则对程序段2进行编译;
#ifdef 标识符
程序段1
#else
程序段2
#endif
2.2 当标识符未被#difine定义过,则对程序段1进行编译,否则对程序段2进行编译;
#ifndef 标识符
程序段1
#else
程序段2
#endif
2.3 当指定的表达式为真,对程序段1编译,否则对程序段2进行编译;
#if 表达式
程序段1
#elif
程序段2
#else
程序段3
#endif
3.优点:
a.减少目标程序长度。
b.可以写多个版本的代码,支持跨平台使用。
指针
1.遍历循环查找,使用指针P的耗时比使用a[i]耗时少。示例代码中将t2和t1之间的程序段移到t4后面,发现t2到t1间的程序耗时最低,这个结论和实际执行情况不一致,待验证。
示例代码
int a[INEE];
int* p;
int i;
a[0] = 12; a[1] = 14; a[2] = 20; a[3] = 18; a[4] = 50;
timeb t1;
timeb t2;
timeb t3;
timeb t4;
ftime(&t1);//获取毫秒
for (i = 0; i < INEE; i++)
{
printf("% d\n", a[i]);
}
ftime(&t2);//获取毫秒
for (i = 0; i < INEE; i++)
{
printf("% d\n", *(a+i));
}
ftime(&t3);//获取毫秒
for (p=a; p < (a+ INEE); p++)
{
printf("% d\n", *(p));
}
ftime(&t4);//获取毫秒
cout << (t2.time- t1.time) * 1000 + t2.millitm - t1.millitm << endl;//758毫秒
cout << (t3.time - t2.time) * 1000 + t3.millitm - t2.millitm << endl;//601毫秒
cout << (t4.time - t3.time) * 1000 + t4.millitm - t3.millitm << endl;//84毫秒
*************************************************************************************
指针数组和数组指针
1.指针数组:int *p[10],这是一个数组,数组有10个元素,每个元素是一个指针。适合传递参数时,参数个数不确定&&每个参数的长度不确定的情景;
举例1:
const char *pName[] = {"C++","java","python"};
sizeof(pName) = 12;//占用12字节,每个指针4字节;
int isize = sizeof(pName) /sizeof(pName[0]); //结果3,表明数组元素有3个;
举例2:
int main(int argc,char argv[]){};
main a1,b2
输出:
argc=4;
argv[0]=main可执行程序的完整路径文件名称
argv[1]=a1
argv[2]=b2;
2.数组指针:int (*p)[10],这是一个指针变量,指向含有10个元素的一维数组。
3.每个数组都会内存中单独开辟一块区域;字符串常量会在内存中开辟一块单独的区域存放字符串常量;
char my1[] = "i love china";//单独开辟内存1
char my2[] = "i love china";//单独开辟内存2
const char *ptr1 = "i love china";//单独开辟内存3(存放字符串常量的内存是只读的),ptr1 指向内存3
const char* ptr2 = "i love china";//ptr2 指向内存3
*************************************************************************************
用函数指针变量调用函数,指针变量可以方便调用功能不同的同类函数
1.定义形式: 数据类型标识符 (*指针变量名)(形参列表)
2.vs等开发环境内部处理手段,把max1等函数入口地址保存到一张表格中,函数调用时到该表中取真实的函数入口地址再调用函数。所以看到max1的内存检测地址和输出值不同;
int (*p)(int x, int y);
p = max1;
BooleanTmp = (p == max1); //结果为true
printf("max=0x%x\n", max1);//内存检测地址是max1 = 0x00007ff6e4372060,输出值是max=0xe4371465;
printf("p=0x%x\n", p);//内存检测地址是p = 0x00007ff6e4371465 ,输出值是p=0xe4371465;
把指向函数的指针变量作为函数参数
1.定义形式:数据类型标识符 (*指针变量名)(形参列表)
2.提高灵活性
int wwmax(int x, int y, int (*p)(int, int))
{
return p(x, y);
}
main(){
c = wwmax(10, 19, max1);
d = wwmax(10, 19, min1);
}
位运算
1.常用方法
#define BIT(x) (1<<(x)):左移x位
enum EnumTask
{
ETask1 = BIT(0),
ETask2 = BIT(1),
ETask3 = BIT(3),
};
unsigned int task = 0; //只需要定义一个变量task,就可以检查32位状态
task = task | ETask2;
if (task & ETask2)
{
cout << task << endl;
cout<< "任务2已完成"<<endl;
}
文件
1.十六进制在内存中是两个数字占用一个字节,内存中一个地址占用一个字节数据。
2.对数字来说,字符串方式存储可能比按数字方式存储浪费更多空间,但双击后人类能看懂。
举例:10000在内存中按字符串形式存储,占用5字节:31 30 30 30 30,按数字形式存储占用2字节:27 10
3.判断文件是否结束函数:feof(fp);
4.fp不使用要及时关闭。
4.1、释放这个文件占用的内存资源,防止资源耗尽。
4.2、往文件中写数据时是先写入“缓冲区”,缓冲区满后再写入磁盘。如果未写入磁盘,此时程序异常退出,会造成数据丢失。
5.结构体成员的字节对齐问题,和编译器相关。例如linux和windows的对齐方式不同,会导致sizeof(stu)结果不同,解决方案是在定义结构体前手动设置结构体对齐方式
例如:#pragma pack(1) //按1字节对齐结构体,等于告诉编译器不要去对齐
struct stu{
char name[30];
int age;
}
#pragma pack() //恢复默认的字节对齐方式
参考文献:
- C++大神Cherno 的视频课程:B站BV号:BV1uy4y167h2 或者油管栏目https://www.youtube.com/watchv=18c3MTX0PK0&list=PLlrATfBNZ98dudnM48yfGUldqGD0S4FFb&index=1