C语言 | 陷阱:数组溢出导致内存被意外修改

C语言的指针在提供编程便利的同时,却带来了很多潜在的内存安全问题。见以下例子: 该程序(不正确)的输出为: 上述代码使用sprintf修改了string_buff指针所指向的char型数组。但是由于在申明数组长度的时候,没有考虑到字符串结束符’\0’,所以实际写入时不慎篡改了下一位内存地址的内容(此例中为i_not_zero, 使用MinGW gcc)。在实际程序中,此类b […]

C语言 | 陷阱:数组指针作为函数参数返回

再来看一个指针问题,同样的来自一个本科生的代码。这段代码想要实现将一个全是小写字母的字符串转换成对应的大写字母字符串: 然而这段代码没有能实现期望的功能。原因如下: 主程序调用convert_to_upper_case()函数后,堆栈为p分配了内存空间; 函数体正确修改了p对应字符数组的内容,并将p的首地址作为指针返回; 函数返回后,所有临时变量从堆栈中弹出,包括p[100]; 主程序得到返回的指 […]

C语言 | 指针的一个错误赋值

关于指针总是有说不完的故事。 最近给本科的学生带Embedded System课程设计,遇到了一个非常奇怪的bug。有一段代码需要实现I2C通信,核心代码已经由软件库提供了,学生只需要设置结构体后调用API即可。一个学生的代码是这样的: 初看一下没有什么问题:在I2C_init()函数中首先对结构体cfg进行初始化,而在I2C_send()函数中设置了需要发送的数据指针,之后使用I2C的API发送 […]

C语言 | C/C++变量命名规范

目前主流的C/C++命名风格有两种:一种是Windows风格的匈牙利命名法,主要是采用类型前缀 + 变量名首字母大写,另一个就是Unix/Linux命名习惯。我自己采用的是基于Unix的变种,融合了匈牙利命名法的一些优点,在这里分享给大家。 变量名的组成:(模块名) +  (作用域) + (类型前缀) + 变量名 + (变量名后缀),解释如下: 变量名 以小写的英文字母构成,词与词之间用下划线连接 […]

C语言 | C语言的函数指针

函数指针是C语言指针中的一个分支:函数指针是指向函数地址的指针。和一般的指针一样,函数指针可以大大增强编程时的灵活性。这篇博文根据我的理解,简单介绍了自己对于函数指针的理解。 一、函数名的本质 在介绍函数指针之前,我们先来理解一下究竟什么是函数。以下一段代码定义了名为fun1(),接受int并返回int参数的函数: 从一般的理解角度来看,fun1是函数的函数名。之所以要定义函数名,是因为在程序的其 […]

C语言 | 陷阱:一个Break在if语句中的误用

C语言以高效著称,但其也存在很多晦涩的语法。让我们来看下面这段(真实的)代码: 以上代码的break意外跳出了case语句。之所以会产生这样的错误,是因为break在for和while中有类似的应用。我的这位朋友是在没有意识的情况下写出了上面这段代码。不仅如此,编译器(甚至高级的排错工具)对此也不会产生疑问,因为break在case语句之中是可以合法存在的。这里我用VS 2010测试了一下,如果该 […]

C语言 | 陷阱:一个优先级导致的BUG

虽然我在工作中已经非常注意优先级的问题,可还是不小心犯了一个优先级导致的错误: 这句话的本意是等待SR寄存器的某位变为1才继续往下执行,而实际上,因为”==”的优先级大于”&”,这句话等同于: 即 while (0); 所以每次执行到该句话时,不管当前SR寄存器的内容是什么,都会直接跳过while。为了防止出现优先级错误,正确的写法应该是: […]

C语言 | C语言运算符优先级

运算符优先级是C语言重要的组成部分,也是程序bug的常见产生源。需要特别注意的有: 赋值在C语言中的优先级是最低的; 位运算的优先级高于逻辑运算; 关系运算符的优先级低于移位,但是高于位运算; 单目运算的优先级最高; 同优先级的运算符按照从左向右的顺序解释。 Table 1. C语言运算符优先级 成员括号 ()   []   ->   . 单目运算  !   ~   ++   — […]

C语言 | 简易拼音输入法

Automatic.dai : 之前在Ourdev论坛上看到有人用C51设计了拼音输入法,代码还没有看,但是对于其实现原理很感兴趣,所以自己简单尝试了一下。 主要原理: 建立一张汉字索引表,主键为拼音,如”bao”,内容为汉字码表,如”包宝饱报抱保苞胞褒雹堡豹鲍暴爆剥薄瀑”。根据用户输入的拼音去查找对应的汉字码表,之后再根据用户输入的数字输出对应的汉字。这种方式很像LUA的table数据结构,用L […]