C语言笔记
const修饰符
int const* x; //x值不可变 int const x; //x指针不可变 int const * const x; //x和x都不可变 //int const i 和 const int i 等效。
可以将const变量赋值给非const变量;可用非const变量对const变量初始化赋值。
不可将const变量传递给非const形参;
可将非const变量传递给const形参,
类型说明(typedef)
define与typedef
处理时间分别在预处理和编译,typedef定义了新的数据类型。
#define PINT int *
typedef int *intp_t;
const PINT p; //p可变,*p不可变
const intp_t p; //p不可变,*p可变
指针和数组
指向n个元素数组的指针:
int (*p)[10]; //此时定义了1个指针变量p,指向10元素的数组
指针数组:
int *p[10]; //此时定义了10个指针变量,分别指向整型数。
函数指针
int f(char* cp, int i){return 0;} struct _st { UINT32 (*function)(INT8 *, UINT32); } st; st.function = (UINT32(*)(INT8*, UINT32))f; //强制类型转换 typedef void (*fn_type)(char *, int); fn_type fun = (fn_type)f;
格式化输出
printf("<格式化字符串>", <参数表>)
- 格式化规定符:
%d 十进制有符号整数
%u 十进制无符号整数
%f 浮点数
%s 字符串
%c 单个字符
%p 指针的值
%e 指数形式的浮点数
%x, %X 无符号以十六进制表示的整数
%0 无符号以八进制表示的整数
%g 自动选择合适的表示法
%ld long整数
%lf double浮点数
%3d 输出三位整型数,右对齐。
%-3d 输出三位整型数,左对齐。
%03d 输出三位整型数,不足三位左补0。
%9.2f 输出9位浮点数,小数2位,整数6位。小数位超过宽度按四舍五入,整数位超过则按实际输出。
printf("=%3s=", “hello”); //输出 “=hello=” printf("=%.3s=", “hello”); //输出 “=hel=” printf("=%6s=", “hello”); //输出 “= hello=” printf("=%-6s=", “hello”); //输出 “=hello =”
- 一些特殊规定字符
\n 换行
\f 清屏并换页
\r 回车
\t Tab符
\xhh 表示一个ASCII码用16进表示,
其中hh是1到2个16进制数
格式化输入
scanf("<格式化字符串>", <地址表>)
格式化字符串包括:
格式化说明符:与printf基本相同
空白字符:在读操作中略去输入中的一个或多个空白字符
非空白字符:在读入时剔除掉与这个非空白字符相同的字符
说明:
0、输入字符串时,遇到空格即认为输入结束,因此无法输入带空格的字符串;
1、数组名和指针变量名前不用加"&";
2、可限制最大位数:scanf("%10s", p)输入字符数大于10后的字符均被读入下一个读入函数。
3、连续使用多个scanf函数时,由于每个scanf只能用回车完成输入,则每隔一个scanf,就被读入一个回车符(显示出来为空行),为解决此问题,可用fflush()函数。
文件输入输出
一、标准文件函数
FILE *fopen(char *filename, char *type); /*FILE是一个新的数据类型,结构指针。*/
其中第二个参数type的规定:
“r” 打开文字文件只读
“w” 创建文字文件只写
“a” 增补, 如果文件不存在则创建一个
“r+” 打开一个文字文件读/写
“w+” 创建一个文字文件读/写
“a+” 打开或创建一个文件增补
“b” 二进制文件(可以和上面每一项合用)
“t” 文这文件(默认项)
int fclose(FILE *stream); //成功返回0,否则非0 //顺序写: int fprintf(FILE *stream, char *format, ); //返回实际写入字符数,错误时返回负数 int fputs(char *string, FILE *steam); //写入字符串后不自动换行,成功返回0,否则非0 int fputc(int ch, FILE *steam); //成功返回所写字符,否则返回EOF(-1) //顺序读: int fscanf(FILE *stream, char *format, ); char fgets(char *string, int n, FILE *steam); //成功返回string指针,否则空指针 int fgetc(FILE *steam); //成功返回所读字符,否则EOF //随机读写: int fseek (FILE *stream, long offset, int fromwhere); int fread(void *buf, int size, int count, FILE *stream); //读count个字段,每个字段size个字节。 int fwrite(void *buf, int size, int count, FILE *stream); long ftell(FILE *stream); int fflush(FILE *stream); //fflush()将缓冲区内容写入文件并清空缓冲区。 feof()和rewind()
二、非标准文件函数
(ANSI C未定义,UNIX和DOS3.0以上系统均支持该类函数)
int open(char *filename, int access); //成功返回非负值,失败返回-1 int close(int handle); int read(int handle, void *buf, int count); int write(int handle, void *buf, int count); int lseek(int handle, long offset, int fromwhere); long tell(int handle);
其他
预处理符号 # 和 ## 的区别
# 使得后面跟的参数转化为字符串;## 连接前后两个参数(不可放在参数表的最前或最后),但不转化为字符串,多用于生成新的符号名。如:
#define s(a) # a
#define ss(a, b) a_ ## b
char* first_name = s(hello);
char* last_name = “world”;
printf(“%s %s\n”, s(hello), ss(last, name));
//经过宏替换后变为 printf(“%s %s\n”, “hello”, last_name);
变参宏定义
C宏中的变参… …在C宏中称为Variadic Macro,也就是变参宏。比如:
#define myprintf(templt,…) fprintf(stderr,templt,VA_ARGS)
或者
#define myprintf(templt,args…) fprintf(stderr,templt,args)
第一个宏中由于没有对变参起名,我们用默认的宏__VA_ARGS__来替代它。
第二个宏中,我们显式地命名变参为args,那么我们在宏定义中就可以用args来代指变参了。
同C语言的stdcall一样,变参必须作为参数表的最后有一项出现。
当上面的宏中我们只能提供第一个参数templt时,C标准要求我们必须写成:myprintf(templt,);的形式。
这时的替换过程为:myprintf(“Error!\n”,);替换为:fprintf(stderr,“Error!\n”,).
这是一个语法错误,不能正常编译。这个问题一般有两个解决方法。
首先,GNU CPP提供的解决方法允许上面的宏调用写成:myprintf(templt);
而它将会被通过替换变成: fprintf(stderr,“Error!\n”,);
很明显,这里仍然会产生编译错误(非本例的某些情况下不会产生编译错误)。
除了这种方式外,c99和GNU CPP都支持下面的宏定义方式:
#define myprintf(templt, …) fprintf(stderr,templt, ##VA_ARGS)
这时,##这个连接符号充当的作用就是当__VAR_ARGS__为空的时候,消除前面的那个逗号。
那么此时的翻译过程如下: myprintf(templt);被转化为: fprintf(stderr,templt);
这样如果templt合法,将不会产生编译错误。
时间处理
time_t time(time_t *tloc); 如果参数为空,则返回1970-01-01 00:00:00到现在经过的秒数
struct tm *localtime(const time_t *timer); tm结构具有根据time_t解析出来的丰富的信息
char *asctime(const struct tm *timeptr); 转换为可打印的字符串
char *ctime(const time_t *clock); 等效于asctime(localtime(clock))
程序的windows窗口和DOS窗口
windows下编程,常见的子系统有windows和console,主函数分别为WinMain和main,用gcc(cygwin)编译的程序,默认为console子系统,可以通过-mwindows或–subsystem,windows连接选项来改变为windows子系统,但仍然可以使用main作为主函数(估计是编译器中做了一定的判断和相关操作)。改为windows子系统后,程序的console界面就不显示出来了。或者更简单的办法:用UE打开生成的console子系统的exe文件,将0xDC处的字节0x03(console子系统)修改为0x02(windows子系统)即可(vckbase上描述的是PE头偏移0x3C+子系统在PE中的偏移0x5C,但我用gcc编译出来的exe实际地址是0x80+0x5c)
在JAVA中使用C库 (jni)
https://blog.youkuaiyun.com/songze_lee/article/details/76039875
C++笔记
杂项
函数名前的const和函数名后的const:
函数开头的 const 用来修饰函数的返回值,表示返回值是 const 类型。
函数头部的结尾加上const表示常成员函数,不能修改成员变量的值。
构造函数
拷贝构造函数
T(const T & t);
使用场合:
①. 函数的参数是一个对象,并且是值传递方式
②. 函数的返回值是一个对象,并且是值传递方式
③. 用一个对象初始化另外一个对象。如:
T t2 = t1;
T t3(t1)
拷贝赋值
T & operator = (const T & t)
移动构造函数
T(T && t)
移动赋值
T &operator = (T && t)
#include <iostream> using namespace std; class T { public: T() {cout << "normal constructor" << endl;} T (int i) {cout << "normal constructor from int" << endl;} T (T& t) {cout << "copy constructor" << endl;} T &operator = (const T &t) {cout << "operator =" << endl;} }; int main () { T t; //默认构造 T t1 = t; //拷贝构造 T t2; //默认构造 t2 = t; //拷贝赋值 return 0; }
STL
在 STL 中,默认情况下,比较大小是通过<运算符进行的,和>运算符无关。
在 STL 中,对于在未排序的区间上进行的算法,如顺序查找算法 find,查找过程中比较两个元素是否相等用的是==
运算符;但是对于在排好序的区间上进行查找、合并等操作的算法(如折半查找算法 binary_search,关联容器自身的成员函数 find)来说,x和y相等
是与x<y和y<x同时为假
等价的,与==
运算符无关。
重载的++运算符,尽量使用前置++,避免使用后置++。(理由)
强制类型转换
static_cast、reinterpret_cast、const_cast 和 dynamic_cast
http://c.biancheng.net/view/410.html
异常
throw; //继续抛出捕获的异常
异常声明列表
void func() throw (int, double, A, B, C);
C++ 11
智能指针 (c++ 11)
shared_ptr<T> ptr(new T);
http://c.biancheng.net/view/430.html
Lambda表达式(匿名函数)(c++ 11)
[外部变量访问方式说明符] (参数表) -> 返回值类型
{
语句块
}
http://c.biancheng.net/view/433.html
auto和decltype关键字(c++ 11)
http://c.biancheng.net/view/438.html