使用预处理语句“注释掉”代码最安全数组
#if 0 // some statements #endif
printf
返回输出的长度(包括不可见字符),scanf
只返回1(成功)或0(失败)scanf
读取输入到数组时,直接写数组名和&数组名效果相同安全
int array[10]; // 如下两种方式效果一致 scanf("%s", array); scanf("%s", &array);
赋值运算符的返回值大几率为左值(C)或左值的引用(C++),但归根究竟是一个undefined行为,取决于编译器的实现。但如下用法一般能够接受:函数
while ((ch = getchar()) != EOF && ch != '\n') // clear input buffer ; // 分号单独写一行,以避免把下一行代码当成循环体
且此处ch
一般被声明为int
,由于EOF
其实是一个int
编码
const
,能够防止意外修改数组中的数据gets
函数的安全性问题在于,它读取字符串时没法知道其长度,当遇到超长字符串时很容易溢出程序的编译与执行操作系统
首先看几个容易混淆的扩展名指针
.out / .exe
可执行文件,Linux和Unix下用.out
,Windows下用.exe
.o / .obj
编译后产生的还没有连接的中间文件,机器码的初步形式,Linux和Unix下用.o
,Windows下用.obj
.bin
单纯二进制文件,多是代码,也多是数据编译code
.c
生成对应的.o / .obj
).o / .obj
文件生成一个完整的.out / .exe
)执行生命周期
字面值内存
数字作用域
字符
使用L
前缀指定字符为宽字符常量(unicode只是宽字符编码的一种,二者并不相等!)
wchar_t = L'X';
字符串
⚠️指向字符串常量的指针能够被指向别的地方,但字符串常量是不能被改变的!
char* strPtr = "blahblah"; strPtr[2] = 'D'; // 非法操做!! strPtr = "Hmmm"; // It's Okay..
声明指针时,把星号紧挨变量写是一个好习惯:
int* a, b, c; // 很容易误解为a、b、c三个指针,而实际只有a是指针,b和c仅仅是int
在声明字符串指针的同时赋值实际意味将该指针指向字符串的首地址,毕竟C中根本没有真正的字符串类型
char *message = "Hello"; // 实际上等价于 char *message; message = "Hello"; // 而不是 *message = "Hello";
用typedef定义指针类型
以前一直不能理解这种习惯,以为真的很容易把指针误认为数据,命名时加个Ptr后缀很差吗??如今才知道原来是方便定义函数指针时用的。。soga
#define charPtr char* // 危险! charPtr a, b, c; // 只有a被声明为指针,b和c为char数据 // ------------------------------------------------------ typedef char *charPtr; // It's Okay.. charPtr a, b, c; // a、b、c的类型都为char*
⚠️const(只表示道义上不会修改,硬要改仍是能够用别的指针轻易绕开限制,防君子不防小人。。)
声明常量
const int a; int const a;
声明指针
理解: 类型 、星号、变量名,这三个部分的相对顺序老是固定的,星号左边的const
修饰数据,星号右边的const
修饰指针
指向常量的指针变量(彻底等价)
int const * p; const int * p;
指向变量的常量指针
int * const p;
指向常量的常量指针
int const * const ptr;
⚠️连接属性
种类
手动改变连接属性
extern
指定为external(代码块内部使用extern声明变量能够确保使用的是最外部的全局变量)static
将缺省属性为external的声明转变为internal属性⚠️声明 vs. 定义(从新理解了这两个名词。。)
声明Declaration
定义Definition
储存类型
静态变量 - static
用途
自动变量 - auto