观感
C语言之父写的C语言指南,阅读的时候怎么能不怀着一点点崇敬的心情。 这本书的第一观感是真的很薄,一共250+页,从167页开始就是附录了。整个目录只有3页纸,这么薄的书在我的书架上只有《C陷阱与缺陷》能够一战。 进入到正文开始阅读后发现,信息量真的很大,要在这一百多页中介绍C语言的基本使用,信息密度可想而知。读起来并不轻松,不是太推荐C语言纯新人阅读,真怕造成“C语言从入门到放弃”。
目的
这里我摘录一些读书的心得和要点,进一步压缩篇幅,方便自己在时间紧迫的情况下快速梳理所有要点。
准备
为了验证书中的代码和做书中的练习,需要准备一个能够编译和运行C语言程序的环境。为了简便起见,我使用了ubuntu系统,命令行方式编译运行比较方便快捷。 为了少打一些字,提高效率,使用以下Makefile来编译目录下所有的.c文件到对应的可执行文件:
[Makefile]
src :=
$(wildcard
*.c)
obj :=
$(patsubst
%.c,
%.o,
$(src))
out :=
$(patsubst
%.o,
%, $(obj))
%.o:
%.c
gcc -c -o
$@ $<
%: %.o
gcc -o
$@ $^
all:
$(out)
clean:
rm -f
$(obj)
$(out)
这样,每次修改或者新编写了一个C语言程序源文件后,直接在命令行执行 make 就可以了。
基本概念
类型
C程序的3个组成要素:变量、函数、语句C程序处理的数据对象:变量、常量
变量有类型 - int float char short long double常量也有类型
1234 int型1234L long int型1.0 double型1.0f float型1.0L long double型0XFUL unsigned long类型,值为15‘c’, ‘\n’, ‘\123’,’\0x20’ 都是字符型常量字符串或者字符串常量,“hello world\n”printf函数不会自动添加换行符,多条printf并不会自动产生行的输出转义字符序列,escape sequence,\n \t \b \” \\
#include <stdio.h>
int main()
{
printf(
"hello ");
printf(
"world");
printf(
"\n");
return 0;
}
变量必须先声明后使用,声明位置在函数起始处,执行任何语句之前建议每行只书写一条语句,运算符两边加上空格= 右对齐占用几个字符空间,%3.1f 小数点保留几位5 / 9,5.0 / 9.0 ,整数舍位,浮点常数也要写成浮点的样式
int main()
{
float fahr, celsius;
int lower =
0;
int upper =
300;
int step =
20;
printf(
"exercise 1_3\n");
printf(
"\tFahr to Celsius\n");
fahr = lower;
while(fahr <= upper)
{
celsius = (
5.0 /
9.0) * (fahr -
32);
printf(
"%3.0f\t%6.1f\n", fahr, celsius);
fahr = fahr + step;
}
return 0;
}
%o %x %s %%可以出现变量值的位置,都可以用产生该变量的表达式#define 定义符号常量,通常大写,末尾没有分号,预编译替换的时候如果不在引号内,不是更长名字的一部分,都会按照#define替换
#define LEAP 1 /* 闰年*/
int days[
31 +
28 + LEAP +
31 +
30 +
31 +
30 +
31 +
31 +
30 +
31 +
30 +
31];
文本流,包括多行字符,每行包括0个或者多个字符,每行以换行符结尾,文本流以EOF(end of file)结尾,EOF长度超过字符类型,一般定义成FFFFFFFF (-1)c = getchar(),从文本流读入下一个字符,putchar(c)向屏幕输出一个字符
#include <stdio.h>
int main()
{
int c;
while((c = getchar()) != EOF)
putchar(c);
return 0;
}
运算符
自增自减,前缀后缀,n++, ++n使用更大的整数表示范围,用double 类型,当做整数运算关系运算符 == ,!=, >, >=, <, <=位运算符 &, |, ~, <<, >>字符常量,单引号内部的一个字符,数值是一个比较小的整数,’A’, ‘\t’
#include <stdio.h>
int main()
{
double nl;
int c;
nl =
0;
while((c = getchar()) != EOF)
{
if (c ==
'\n')
nl++;
}
printf(
"line number: %.0f\n", nl);
return 0;
}
逻辑运算符 && , ||, !,遵循短路求值函数的定义,存放的位置不重要,只要不跨文件即可函数的参数传递,是值传递,不是引用传递;形参名称只在函数内部有意义编译时遇到函数名,需要已经声明过,但可以不必知道定义在哪里字符串以’\0’标记结束
int strlen(
char s[])
{
int ;
i =
0;
while(s[i] !=
'\0')
++i;
return i;
}
变量
变量类型
自动变量 - 函数内部定义的变量,作用域函数内部,生存期函数执行外部变量 - 函数外部定义的变量,只定义一次,编译器为其分配存储单元。使用的时候先声明
声明在函数内部,从声明的位置起到本函数结束有效声明在函数外部,从声明的位置起到本文件结束有效 外部变量定义在某个c文件中(此文件中使用它不需要声明为extern,直接用就可以),通常声明在h文件中(使用它的各c文件需要Include这个头文件)静态变量
static 全局变量 - 本文件可见,程序的其他文件不可见,名字不会冲突static 局部变量 - 本函数可见,却别于自动变量,函数结束也不会释放复杂类型变量
枚举结构联合
enum months {JAN =
1, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC};
enum months a;
enum months b;
a = JAN;
b = MAY;
变量声明
显式,隐式,形参就是隐式声明声明同时可以进行初始化建议一个变量单独用一行声明全局或者静态变量的声明可以同时进行初始化,初始化的动作只进行一次声明时可以使用const限定符,表示不可以修改,数组的话,表示数组的所有元素都不能修改
一些有意思的小程序
int atoi(
char s[])
{
int i;
int n =
0;
for (i =
0; s[i] >=
'0' && s[i] <=
'9'; ++i)
{
n =
10 * n +(s[i] -
'0');
}
return n;
}
void strcat(
char s[],
char t[])
{
int i, j;
i = j =
0;
while (s[i] !=
'\0')
i++;
while((s[i++] = t[j++]) !=
'\0')
;
}
unsigned getbits(
unsigned x,
int p,
int n)
{
return (x >> (p +
1 - n)) & ~(~
0 << n);
}
x &= (x -
1);