《C Traps and Pitfalls》 笔记

这本书短短的100多页,很象是一篇文章。但是指出的很多问题的确容易出现在笔试的改错题中

--------------------------------------------------------------------
第1章 词法陷阱

1.1 = 和 ==

1.3 词法分析的"贪心法则"
编译器从左到右读入字符,每个符号包含尽可能多的字符,直到不是字符为止

如:
a---b  等价于  a-- - b

a/*b   并不是 a/(*b), 而是/*当作注释符


1.4 整型常量

0开头的整数为8进制

如:
014  为8进制, 不要误看作10进制

1.5 字符和字符串

单引号 - ASCII字符,实际上是一个整数
双引号 - 指向匿名的字符数组起始字符的指针,该数组以引用的字符和额外的'\0'初始化

另外,大多数编译器允许一个字符常量中包含多个字符。Borland C++中只取第一个字符,而VC 6.0和GCC中则后面的字符依次覆盖前面的字符,最后得到的是最后一个字符。

如:(GCC 3.5)
char ch='yes';
cout << ch;//output: s, but with warning

练习题:
1-1。某些C编译器允许嵌套注释。请写一个测试程序,要求:无论对是否允许嵌套注释的编译器,该程序都能正常通过编译(无错误消息),但是这两种情况下程序执行的结果却不同。

1-3. n-->0的含义?
(n--) > 0     贪心法则

1-4 a+++++b的含义?
((a++) ++) + b
但是值得一提的是:现代编译器中,此式子是非法的

为什么?
你可以查看operator++(int)的原型: const int operator++(int)
返回的为const型,且为a的临时拷贝。之所以返回为const型,就是为了将返回作为左值,也就防止出现这类式子
总结:a++不能做左值

---------------------------------------------------------------------------------------
第2章 语法陷阱

2.1 理解函数声明
换个角度理解声明语句(declaration)
声明语句构成:类型 + 一组类似表达式的声明符(declarator)

float f, g; //表达式f, g求值为浮点数,即f, g为浮点型
float ff(); //表达式ff()求值是一个浮点数,即ff是一个返回类型为浮点数的函数
float *pf; //*pf求值是一个浮点数,即pf是指向浮点型的指针
更复杂的,
float *g(), (*h)();
依据上述并且()优先级大于*,很容易知道g是一个函数,返回类型为浮点指针(float *)
h为一个函数指针,函数返回类型为float
(float (*h)()) 是一个类型转换符

再看:
(*(void(*)())0)()
实质上是:
void (*fp)(); //declare a function pointer
typedef void (*fp_type)();// for simplifying, otherwise always need void(*)()
conv_0 = (fp_type)0; // converse function 0 into function conv_o
(*conv_0)();//using the conversed function

再让我们看看<signal.h>中声明的signal函数
void (*signal(int, void(*)(int)))(int)
首先,用typedef简化,
typedef void (*handler_type)(int)
得,void (*signal(int, handler_type))(int)
进一步 handler_type signal(int, handler_type);

2.3 作为语句结束的分号
1)多写了分号
if(x[i] > big);
   big = x[i]
这还是很容易辨识
再看
2)漏写了分号
if(n < 3)
    
return
logrec
.date = x[0];
logrec
.time = x[1];
logrec
.code = x[2];
看出问题来了没?

继续看下面一个经典的:
struct logrec
{
    
int date;
    
int time;
    
int code;
}

main()
{
    
//
}

注:这个问题笔试题已经出现过

2.4 swith语句
这个估计是老生常谈了

也就是case后的break有无的问题了

首先要搞清楚一件事:你可以把(case:)当作语句的标号,就好像汇编中的标号一样。switch之后径直跳到匹配的case处顺序执行下去,以后再碰到case则无视

当然,程序设计中有意不要break的除外

2.6 “空悬”else引发的问题

看下面代码:
if(x == 0)
    
if(y == 0) error();
else{
    z 
= x + y;
    f(
&z);
}
这段代码可能与你的本意大相径庭,因为else与最近的if匹配

防止这类问题很简单,只要每次使用if,else都用{}

---------------------------------------------------------
第3章 语义陷阱

3.1 指针和数组

C语言数组需要注意:
1)C语言只有一维数组,数组大小必须在编译期确定为常数。二维数组是通过数组元素也为数组的一维数组实现
2)对于一个数组,只能做2件事情:确定数组大小,取得指向数组首元素的指针。其他相关操作,如下标运算, 都是通过指针进行

int a[3]; //数组元素为int型
struct
{
    int p[4];
    double x;
}b[17]; //数组元素为结构体
int calendar[12][31];
//12个元素的数组,每个元素又是31元素的数组
//并非:31个元素的数组,每个元素是12个元素的数组


记住:数组名是指向该数组首元素的指针
如,int a[11];  //那么a的类型为 (int *)
int *ptr;
ptr = a;
但是ptr = &a;是非法的,这里&a的类型为int (*)[],即指向数组的指针,大多数编译期对这种操作,或者视为非法,或者让其等于a

在C中,a+i和i+a的含义是一样的,但后者不推荐

下面看多维数组:
int calendar[12][31];
int *p;
int i;

我们很容易知道calendar[4]表示什么含义:calendar[4]表示calendar数组的第5个元素,是12个有31个元素的数组之一。
sizeof(calendar[4])结果为31×sizeof(int)

此例中,calendar名字转换为一个指向数组的指针,其类型为int (*)[31]
于是p=calendar; 是非法的

int (*monthp)[31];
monthp = calendar;//OK


calendar[month][day] = 0;
等价于
*(*(calendar+month)+day) = 0;
怎样分析这个呢?
首先,calendar+month是指向12个元素之一的指针,对其解引用得到就是其元素(而元素是数组),所以*(calendar+month)是指向含31个元素的数组首元素的指针,再偏移然后解引用即得到最终的int型元素

总结:
1)数组名表示指向首元素的指针,类型为元素类型的指针
2) 对数组名取地址,为指向数组的指针,类型为数组的指针

3.2 非数组的指针 - 字符串

字符串常量:代表一块包含字符串中所有字符加上额外一个空字符('\0')的内存区的地址。

一般字符串常量用字符数组保存的,且是只读的。

字符串操作函数:
size_t strlen(char *);//计算字符串长度,直到遇到'\0'.且不包括'\0'
int strcpy(char * dest, const char *src);
int strcat(char *dest, char *src);

注意其中的输出参数dest必须是预先分配好,且有足够的空间能容纳


3.3 数组作为函数参数

自动转换成指针

3.6 边界计算与不对称边界

这个主题值得探讨

3.7 求值顺序

C中只有四个运算符(&&, ||, ? :和,)规定了求值顺序,对于其他运算符不要错误的假设求值顺序,他们求值顺序是未定义的。

如:
i = 0;
while(i < n)
    y[i] = x[i++];

这里y[i]的地址在i自增前被求值是没有任何保证的


3.9 整数溢出

C语言中存在2类整数算术运算:有符号运算与无符号运算。

两个无符号数运算不存在溢出。

算术运算中一个是有符号数,另一个是无符号数,则有符号数会转换为无符号数,运算时溢出也不可能发生。

两个有符号数运算,溢出有可能发生。并且溢出发生时,溢出结果是未定义的。

那么如何检测是否发生溢出呢?
看下面的方式:
int a, b;
if(a + b < 0)
    //do something

这种方式是不可靠的,因为对溢出结果做的任何假设都是不可靠的

正确的方式:
#include <limits.h>
int a, b;
if((unsigned)a + (unsigned)b > INT_MAX)
    //...
或者
if(a > INT_MAX - b)
    //...

--------------------------------------------------------------------------------------
第4章 连接

4.2 声明与定义

下面声明语句:
int a;
如果出现在所有函数体(包括main函数)之外, 它被成为外部对象a的定义,并且其初始值默认为0

下面声明语句:
int a = 7;
定义a的同时指定了初始值

下面声明语句:
extern int a;
并不是a的定义,说明a是一个外部整型变量,它的存储空间在程序的其他地方分配

典型情况:
//file1.c
int a = 7;

//file2.c
int a = 9;

这种情况一般在连接时会报错,因为定义只能一次,声明却可以很多

4.3 命名冲突与static修饰符

static将变量或函数的作用域限定在一个源文件中了

4.5 检查外部变量

转载于:https://www.cnblogs.com/chio/archive/2007/10/26/938064.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/423938.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

spring mvc学习(53):回顾和springmvc返回值类型总结

媒体类型 MIME媒体类型&#xff08;简称MIME类型&#xff09;是描述报文实体主体内容的一些标准化名称&#xff08;比如&#xff0c;text/html、image/jpeg&#xff09;。 因特网有数千种不同的数据类型&#xff0c;HTTP仔细地给每种要通过web传输的对象都打上了名为MIME类型的…

2019hdu多校1

1009 考虑贪心&#xff0c;暴力枚举一位。 $o(676n)$ #include<bits/stdc.h> using namespace std; const int N1e5333; int n,m,zl; int pos[26],cnt[N],t[26],az[N]; char s[N],st[N]; int l[N],r[N],nx[N],zzq[26]; int main(){ios::sync_with_stdio(0);//freopen(&qu…

关于梅花雪的js树

最近一段时间&#xff0c;为了学习java&#xff0c;天天在看别人的框架&#xff0c;为了实现一颗树&#xff0c;找到了一个改写梅花雪的js&#xff0c;下面是一个基本的结构<% page language"java" import"java.util.*" pageEncoding"GBK"%&g…

总和最大区间问题

题目和解题思路来源于吴军著作《计算之魂》。本题目是例题1.3。 文章目录1 问题描述2 解题思路2.1 三重循环2.2 两重循环2.3 分治法2.4 正反两遍扫描的方法2.5 再进一步&#xff0c;假设失效3 应用动态规划1 问题描述 总和最大区间问题&#xff1a;给定一个实数序列&#xff0…

spring mvc学习(54):简单异常处理

引入jar包 pom.xml <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">…

spring mvc学习(55):简单异常处理二

引入jar包 pom.xml <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">…

Jelinek-Merer与Absolute discounting 平滑方法

Jelinek-Merer Jelinek-Merer平滑方法的基本思想是利用低元n-gram模型对高元n-gram模型进行线性插值。 PML(wi∣wi−1)c(wi,wi−1)c(wi−1)P_{ML}(w_i|w_{i-1})\dfrac{c(w_i,w_{i-1})}{c(w_{i-1})}PML​(wi​∣wi−1​)c(wi−1​)c(wi​,wi−1​)​ c(wi,wi−1)c(w_i,w_{i-1}…

从决策树到xgboost(一)

文章目录1 决策树1.1决策树定义1.2信息增益1.3 信息增益的算法1.4 信息增益比2 决策树ID32.1 ID3树的构建2.2 决策树的剪枝2.2.1 损失函数定义与计算2.2.2 剪枝过程2.3 CART树2.3.1 CART回归树2.3.2 CART分类树2.3.3 CART树剪枝1 决策树 1.1决策树定义 决策树的基本组成&…

从决策树到xgboost(二)

文章目录3 集成学习4 Adaboost4.1 Adaboost算法4.1.1 初始化训练数据的起始权值分布4.1.2 对m个弱分类器m1,2,3...M4.1.3 构建弱分类器的线性组合4.1.4 得到最终的分类器5 Boosting5.1 加法模型5.2 前向分布算法6 提升决策树BDT6.1 BDT算法6.2 回归问题提升树7 梯度提升决策树G…

[伤了昨天的心 裂成碎片和沙一起飞]五香里脊

今晨3点挂的电话&#xff0c;6点睁开的眼。困到头痛&#xff0c;但还是烧了道肉菜。…**…**…**…**…**…**…**…*分隔 五香里脊*…**…**…**…**…**…**…**…五香里脊 材料&#xff1a;1&#xff0e;里脊肉、油、麻油。2&#xff0e;蒜末、辣椒末、水、生抽、老醋、糖、…

MOTOMAN-SV3X运动学建模验证图

以下是正解&#xff0c;逆解 结果 转载于:https://www.cnblogs.com/wqj1212/archive/2008/01/01/1022177.html

小程序·云开发实战 - 迷你微博

0. 前言 本文将手把手教你如何写出迷你版微博的一行行代码&#xff0c;迷你版微博包含以下功能&#xff1a; Feed 流&#xff1a;关注动态、所有动态发送图文动态搜索用户关注系统点赞动态个人主页使用到的云开发能力&#xff1a; 云数据库云存储云函数云调用没错&#xff0c;几…

spring mvc学习(60):ssm项目整合

SSM整合 建立springmvc项目&#xff0c;先跑起来&#xff0c;再整合spring和mybatis 一.SpringMVC建立 1.新建maven工程&#xff0c;安装tomcat 2.导入pom <!-- springmvc --><dependency><groupId>org.springframework</groupId><artifactId>…

回溯算法归纳

回溯算法解题思路回溯的两种思路题目描述按照思路1解决按思路2解决回溯的两种思路 看不同的解题方法&#xff0c;形成不同的思维。 先说结论。回溯解题思路1&#xff1a;是对可选择每个元素&#xff0c;采取不选择、选择两种策略&#xff0c;不断递归下去。最近看花花酱的视频…

mybatis学习(1):【持久化框架】Mybatis简介与原理

从这篇博文开始我们学习一下Mybatis&#xff0c;希望大家提出宝贵的建议。 什么是Mybatis MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code&#xff0c;并且改名为MyBatis 。iBATIS一词来源于“internet”和“abati…

UML类图解义

小菜&#xff1a;“对了&#xff0c;我时常在一些技术书中看到这些类图表示&#xff0c;简单的还看得懂&#xff0c;有些标记我很容易混淆。要不你给我讲讲吧。” 大鸟&#xff1a;“这个其实多看多用就熟悉了。我给你举一个例子&#xff0c;来看这样一幅图&#xff0c;其中就包…

mybatis学习(2):基本设置和核心配置

1创建一个简单的java项目 2导入jar包 建立一个lib包 链接&#xff1a;https://pan.baidu.com/s/1eJ7xXF2qvUbgde2T--Sphg 提取码&#xff1a;3bgy 加入junit的包 右键项目---build path---add library 4导入配置文件 log4j.properties ### ### log4j.rootLogger ERROR,s…

mybatis学习(3):映射文件的配置和接口创建

配置文件 db.properties jdbc.drivercom.oracle.jdbc.OracleDriver jdbc.urljdbc:oracle:thin:127.0.0.1:1521:wiicare jdbc.usernamewiicare jdbc.passwordMdsd123 log4j.properties ### ### log4j.rootLogger ERROR,stdout### ¡ ### log4j.appender.stdout org.ap…

mybatis学习(4):工具类和实体类的创建

配置文件 db.properties jdbc.drivercom.oracle.jdbc.OracleDriver jdbc.urljdbc:oracle:thin:127.0.0.1:1521:wiicare jdbc.usernamewiicare jdbc.passwordMdsd123 log4j.properties ### ### log4j.rootLogger ERROR,stdout### ¡ ### log4j.appender.stdout org.ap…

windows下解决pip安装出错问题

今天使用pip install xxx突然报错&#xff0c;找了好久全是在linux上的解决方案&#xff0c;好不容易找到一个windows下的解决方案&#xff0c;所以将他记录下来。 解决方案&#xff1a; cmd中敲命令&#xff1a;python -m ensurepip 得到pip的setuptools 然后就可以用&#xf…