C++ and VS

VS知识

快捷键

Ctrl-K + Ctrl-C 注释一段选择代码
Ctrl-K + Ctrl-U 取消一段选择代码的注释
Ctrl-K + Ctrl-D 格式化整篇代码

为解决方案创建目录后那么根目录包含

  • .sln
  • .db
  • git文件夹
  • solution文件夹: 与工程同名, 放源代码.

  • 以及x64文件夹,用于放编译出来的项目.

在solution文件夹中, 比如项目名是test, 那么源代码就在./test/test/里面, 第一个test指的是解决方案目录, 第二个就是项目名. 包含

  • 所有的源代码, .cpp和.h等等
  • .vcxproj
  • .vcxproj.filters
  • .vcxproj.user

  • 这也是默认的输入输出的根目录,也就是说,如果程序中打开或新建一个文件,只给文件名的话,就从这个目录打开.

疑问

为什么项目总是让我们编译

查看工具->选项->项目和解决方案->MSBuild项目生成输出详细级别

再把 视图->输出 中的内容复制到txt中 寻找类似语句
“项目不是最新的,因为缺少…”

修复后对解决方案或项目选择全部生成。之后运行就正常了

Note:

  • 不是“MSBuild项目生成日志文件详细级别”,那个内容不够丰富,会遗漏一些

  • 修复后不是立即运行,而是对解决方案或项目选择全部生成

如何查看导入到系统库lib路径

工程项目属性页->配置属性->VC++目录的库目录可以看到所调用的系统文件夹路径
某台电脑缺乏一些库(因为之前使用了卸载VS的专门工具)导致不能编译,因此在可以编译的计算机上使用Everything找到相应的lib,再拷贝到那个电脑

如何在VS里添加头文件包含路径

项目->属性->C++->附加包路径

C++知识

知识

注意事项

C++内部变量连续存储,意味着先定义了a数组a[100]后定义了b,那么如果a[105]原先是未定义的 但是当把b置0后,a[105]的值也会跟着改变,因为a[105]地址可能就是b的地址

指针

初始化a指向整型数组
int* a = new int[5];

初始化a指向5这个整型
int* a = new int(5);

拷贝

拷贝数组至另一个数组(数组元素为N个)

拷贝数组a至数组b:memcpy(b, a, sizeof(float)*N);
拷贝数组a至向量b:memcpy(&b[0], a, sizeof(float)*N);
拷贝向量a至向量b:memcpy(&b[0], &a[0], sizeof(float)*N);

拷贝二维数组的一部分(N列)至向量b(N个元素)

拷贝二维数组的第一行至向量b:memcpy(&b[0], a, sizeof(float)*N);
拷贝二维数组的第二行至向量b:memcpy(&b[0], a+1 sizeof(float)*N);
拷贝二维数组的第二行第三个元素开始的N个元素至向量b:
memcpy(&b[0], *(a+1)+2,sizeof(float)*N);
或者memcpy(&b[0], &a[1][2],sizeof(float)*N);
因为&a[i]=a+i&a[i][j]=*(a+i)+j,在指向行的指针前加 * ,转换为指向列的指针;在指向列的指针前加 & ,转换为指向行的指针;

测量时间

1
2
3
4
5
6
#include "time.h"
clock_t start, end;
start = clock();
//code here
end = clock();
printf("Elapsed time:%f secs.\n", (double)(end - start) / CLOCKS_PER_SEC);

函数

  • sprintf
1
2
int sprintf( char *buffer, const char *format, [ argument] … )//把格式化的数据写入某个字符串缓冲区buffer中
sprintf(szLstFile,"%s\\lists\\phoneme.lst",g_LibCfg.szPrjDir);//把 g_LibCfg.szPrjDir 按照 "%s\\lists\\phoneme.lst"格式转化,并存在 szLstFile 中
  • sscanf
    1
    int sscanf(const char *buffer,const char *format,[argument ]...);  //sscanf会从buffer里读进数据,依照format的格式将数据写入到argument里。
  • fgets
    1
    char *fgets(char *buf, int bufsize, FILE *stream);//从文件结构体指针stream中读取数据,每次读取一行。读取的数据保存在buf指向的字符数组中,每次最多读取bufsize-1个字符(第bufsize个字符赋'\0')
  • fgets返回值
  1. 成功,则返回第一个参数buf
  2. 在读字符时遇到end-of-file,则eof指示器被设置,如果还没读入任何字符就遇到这种情况,则buf保持原来的内容,返回NULL
  3. 如果发生读入错误,error指示器被设置,返回NULL,buf的值可能被改变
  • fscanf
    1
    2
    int fscanf(FILE*stream, constchar*format, [argument...]); //其功能为根据数据格式(format)从输入流(stream)中写入数据(argument);与fgets的差别在于:fscanf遇到空格和换行时结束,注意空格时也结束,fgets遇到空格不结束。
    fscanf(fpPhone," %s %s",szTmpStr,szTmpStr);//只会将第二个字符串赋值给szTmpStr
  • fread
    1
    size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );//从文件流指针stream处读count个数据,每个数据大小size个字节,放到ptr中存储。
  • fwrite
    1
    size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream )//fwrite()用来将数据写入文件流中,将ptr指向的数据地址的内容输出至stream文件指针指向的文件
  • memset
    1
    2
    void *memset(void *s, int ch, size_t n);//函数解释:将s中当前位置后面的n个字节(typedef unsigned int size_t )用 ch 替换并返回 s
    //memset:作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法
  • strstr
    1
    extern char *strstr(char *str1, const char *str2);//返回值;若str2是str1的子串,则返回str2在str1的首次出现的地址;如果str2不是str1的子串,则返回NULL。
  • strncpy
    1
    char *strncpy(char *dest, const char *src, int n)//把src所指向的字符串中以src地址开始的前n个字节复制到dest所指的数组中,并返回dest。
  • strcpy
    1
    char *strcpy(char *dest, const char *src);//strcpy()会将参数src 字符串拷贝至参数dest 所指的地址。
  • strcmp
    1
    2
    3
    4
    extern int strcmp(const char *s1,const char *s2);
    //当s1<s2时,返回为负数
    //当s1=s2时,返回值= 0
    //当s1>s2时,返回正数
  • memcpy
    1
    void * memcpy ( void * destination, const void * source, size_t num );//从source处读num个字节放到destination指向的内存中去。
  • assert
    assert宏能测试传入表达式的真假值,当表达式为真(true),则不会有任何反应;当表达式为假(false),则函数将输出错误信息,并中断程序的执行。

疑问

如何在sprintf函数中使用string?

sprintf是C++继承自C语言的函数,无法直接支持string类型,所以要先把string类型转为基础类型,也就是char*。
这里需要使用string类的成员函数c_str();该成员函数功能为,将string的内容转为C语言的字符数组表达形式。
所以用sprintf将string对象str,输出的char[]数组array中的代码可以写作: sprintf(array, "%s", str.c_str());
除此外,还可以用strcpy函数,使代码更简单:strcpy(array, str.c_str());

实际例子

建立二维数组

1
2
3
4
5
6
7
8
9
10
11
//开辟内存
float **ppTrgAnswer_Data = new float*[nTrgPhoneNum];
for (int i = 0; i < nTrgPhoneNum; i++)
{
ppTrgAnswer_Data[i] = new float[MAX_QUES_NUM];
memset(ppTrgAnswer_Data[i], 0, sizeof(float)*MAX_QUES_NUM);
}
//释放内存
for (i = 0; i < nTrgPhoneNum; i++)
delete[] ppTrgAnswer_Data[i];
delete[] ppTrgAnswer_Data;