Chinaunix首页 | 论坛 | 博客
  • 博客访问: 317336
  • 博文数量: 26
  • 博客积分: 2510
  • 博客等级: 少校
  • 技术积分: 915
  • 用 户 组: 普通用户
  • 注册时间: 2007-06-20 14:54
文章分类

全部博文(26)

文章存档

2010年(3)

2009年(14)

2008年(9)

我的朋友

分类: C/C++

2009-03-05 20:18:51

C,是一种通用的,它主要用来进行。具有高效、灵活、功能丰富、表达力强和好等的特点,在程序员中备受青睐。

C语言是由的研制者(Dennis Ritchie)和(Ken Thompson)于1970年研制出的的基础上发展和完善起来的。C语言可以广泛应用于不同的,例如、、及等。C语言是一种,同时具有和的优点。在C语言的基础上发展起来的有支持多种的语言,网络上广泛使用的、,微软的等。

,(ANSI) 对C语言进行了标准化,于1983年颁布了第一个C语言标准草案(83 ANSI C),后来于1987年又颁布了另一个C语言标准草案(87 ANSI C)。最新的C语言标准是在1999年颁布并在2000年3月被ANSI采用的 C99 ,但由于未得到主流编译器厂家的支持,直到C99 并未被广泛使用,增加了若干新特性后 C99 已经逐渐让C语言和分道扬镳。

目录

[]
[]

C语言的特色

  • C语言是。流行的操作系统核心部分几乎无一例外的选择了C语言。
  • C语言保留了的特性,例如C语言允许使用来对任意做直接修改。
  • C语言使用了机制,使得程序员可以在编译之前对程序结构做出控制。常用的预处理机制包括宏与编译选择等。

C语言的主要不足是缺乏对真实事物的描述手段。用C语言表达复杂的将 会十分困难,而且代码量也明显高于C++语言。同时C语言过度的信赖程序员的做法也一直存在很大争议,是否允许程序员随意修改内存中的任何东西一直都是争 论的焦点所在。C语言的不足可以由C语言发展而来的新的编程语言所改进。Cyclone语言拥有提防内存错误的特性。C++和Objective C提供了用于的编程结构。和在提供面向对象编程结构的同时,也提供了垃圾收集机制,这使得对内存的管理更加透明与自动化。

[]

C語言的主要特性

  • C語言保留了低階語言的特性,例如涉及的指針。
  • C語言通過參數在函數裏傳遞數值。
  • 使用了機制,使得程式裏可以通過包含例如巨集處理的方式來處理。
  • C語言提供了一套標準庫,這些庫裏提供了十分有用的功能。

但是並不是所有的這些特性都是有效的。例如,預處理通常作為一個獨立的程式被處理,這使得預處理的程式並不一定被完全編譯。

雖然C是高階語言,但是它同時擁有一些組合語言的特性,對其他的語言來說這是接近低階語言的特點。例如,在C語言裏,程式師可以對電腦記憶 體進行管理。在默認的情況下,C語言不會對陣列的範圍進行檢查,也就是說即使陣列越界,C語言也不會作出錯誤提示。對電腦記憶體的管理使得程式員可以編出 更快捷、更有效的程式,這對於設備驅動程式來說尤為重要。但是這也使得程式容易產生令人討厭的「」,例如緩衝器溢出錯誤。然而,這些錯誤可以由一些工具來避免。

C語言的不足可以由從C語言發展而來的更新的編程語言改進。Cyclone語言的擁有提防對於記憶體錯誤的特性。C++和Objective C提供了用於面向物件的編程結構。Java和C#增加了面向物件的結構使得對記憶體的管理自動化。

[]

C語言的歷史

C語言的第一次發展在1969年到1973年之間。C之所以被稱為C是因為C語言的很多特性是由一種更早的被稱為B語言的編程語言中發展而來的。

到了1973年,C語言已經可以用來編寫Unix操作系統的內核。這是第一次用C語言來編寫操作系統的內核。丹尼斯·裡奇和Brian Kernighan在1978年出版了《C程序設計語言》(The C Programming Language,經常簡稱為「白皮書」或「K&R」)。

1980年以後,使得C變得更為廣泛的流行,使得C一度成為了操作系統和應用程序編程的首選。甚至到今天,它仍被廣泛用於編寫操作系統以及作為廣泛的計算機教育的語言。2005年4月,C++之父稱C++用戶超過300萬。

1980年代晚期,和為C語言添加了面向對象的特性.這種語言成為了。C++現在廣泛應用的在下運行的商業應用程序的編制,然而C仍然是的熱門編程語言。

[]

C语言的版本

[]

K&R C

C不断的从它的第一版本进行改进。在1978年,和里奇的《C程序设计语言》第一版出版。它介绍了下面的有关C语言版本的特性:

  • struct数据类型
  • long int数据类型
  • unsigned int数据类型
  • 把运算符=+改为+=,依次类推。因为=+使得编译器混淆。

在以后的几年里,《C程序设计语言》一直被广泛作为C语言事实上的规范。在这本书中,C语言通常被表述成“K&R C”。(第二版的包括了ANSI C标准)

K&R C通常被作为C编译器所支持的最基本的C语言部分。虽然现在的编译器并不一定都完全遵循ANSI标准,但K&R C作为C语言的最低要求仍然要编程人员掌握。但是无论怎样,现在使用广泛的C语言版本都已经与K&R C相距甚远了,因为这些编译器都使用ANSI C标准。 //....

[]

ANSI C和ISO C(1985年)

1989年,C语言被ANSI标准化。(ANSI X3.159-1989)。标准化的一个目的是扩展K&R C。这个标准包括了一些新的特性。在K&R出版后,一些新的特征被“非官方”的加到C语言中。

  • void函数
  • 函数返回structunion类型
  • void *数据类型

在ANSI标准化自己的过程中,一些新的特征被加了进去。ANSI也规定了一套标准函数库。ANSI ()成立 ISO/IEC JTC1/SC22/WG14工作组来规定国际标准的C语言。通过对ANSI标准的少量修改,最终通过了ISO 9899:1990。随后ISO标准被ANSI采纳。

传统C语言到ANSI/ISO标准C语言的改进包括:

  • 增加了真正的标准库
  • 新的预处理命令与特性
  • 函数原型允许在函数申明中指定参数类型
  • 一些新的关键字,包括constvolatilesigned
  • 宽字符、宽字符串与字节多字符
  • 对约定规则、声明和类型检查的许多小改动与澄清
[]

ANSI C和ISO C(1995年)

作为对标准的维护与更新,WG14工作小组在对1985年颁布的标准做了两处技术修订(缺陷修复)和一个补充(扩展)。下面是1995年做出的所有修改:

  • 3个新的标准库头文件 iso646.h、wctype.h和wchar.h
  • 几个新的记号与预定义宏,用于对国际化提供更好的支持
  • printf/sprintf函数一系列新的格式代码
  • 大量函数和一些类型与常量,用于多字节字符和宽字节字符


[]

C99

在ANSI标准化后,WG14小组继续致力于改进C语言。新的标准很快推出,就是ISO9899:1999(出版)。这个版本就是通常提及的C99。它被ANSI于三月采用。

在C99中包括的特性有:

  • 对编译器限制增加了,比如源程序每行要求至少支持到 4095 字节,变量名函数名的要求支持到 63 字节 (extern 要求支持到 31)
  • 预处理增强了。例如:
    • 支持取参数 #define Macro(...) __VA_ARGS__
    • 使用的时候,参数如果不写,里用 #,## 这样的东西会扩展成空串。(以前会出错的)
    • 支持 // 行注释(这个特性实际上在C89的很多编译器上已经被支持了)
  • 增加了新关键字 restrict, inline, _Complex, _Imaginary, _Bool
    • 支持 long long, long double _Complex, float _Complex 这样的类型
  • 支持 <: :> <% %> %: %:%: ,等等奇怪的符号替代,D&E 里提过这个
  • 支持了不定长的数组。数组的长度就可以用变量了。声明类型的时候呢,就用 int a[*] 这样的写法。不过考虑到效率和实现,这玩意并不是一个新类型。所以就不能用在全局里,或者 struct union 里面,如果你用了这样的东西,goto 语句就受限制了。
  • 变量声明不必放在语句块的开头,for 语句提倡这么写 for(int i=0;i<100;++i) 就是说,int i 的声明放在里面,i 只在 for 里面有效。
  • 当一个类似结构的东西需要临时构造的时候,可以用 (type_name){xx,xx,xx} 这有点像 C++ 的构造函数
  • 初始化结构的时候现在可以这样写:
      struct {int a[3], b;} hehe[] =  { [0].a = {1}, [1].a = 2 };
struct {int a, b, c, d;} hehe = { .a = 1, .c = 3, 4, .b = 5} // 3,4 是对 .c,.d 赋值的
  • 字符串里面,\u 支持 unicode 的字符
  • 支持 16 进制的浮点数的描述
  • 所以 printf scanf 的格式化串多支持了 ll / LL (VC6 里用的 I64) 对应新的 long long 类型。
  • 浮点数的内部数据描述支持了新标准,这个可以用 #pragma 编译器指定
  • 除了已经有的 __line__ __file__ 以外,又支持了一个 __func__ 可以得到当前的函数名
  • 对于非常数的表达式,也允许编译器做化简
  • 修改了对于 / % 处理负数上的定义,比如老的标准里 -22 / 7 = -3, -22 % 7 = -1 而现在 -22 / 7 = -4, -22 % 7 = 6
  • 取消了不写函数返回类型默认就是 int 的规定
  • 允许 struct 定义的最后一个数组写做 [] 不指定其长度描述
  • const const int i; 将被当作 const int i; 处理
  • 增加和修改了一些标准头文件, 比如定义 bool 的 定义一些标准长度的 int 的 定义复数的 定义宽字符的 有点泛型味道的数学函数 跟浮点数有关的 里多了一个 va_copy 可以复制 ... 的参数。 里多了个 struct tmx 对 struct tm 做了扩展
  • 输入输出对宽字符还有长整数等做了相应的支持

但是各个公司对C99的支持所表现出来的兴趣不同。当GCC和其它一些商业编译器支持C99的大部分特性的时候,和却似乎对此不感兴趣。

[]

C语言的Hello World程序

下面是一个在标准输出设备上输出的简单程序,这种程序通常作为开始学习编程语言时的第一个程序:

#include 
 
int main(void)
{
printf("Hello, world!\n");
return 0;
}
[]

进一步了解C

C语言由函数和变量组成。C的函数就像是中的子程序和函数。

在C语言中,程序从main开始执行。main函数通过调用和控制其他函数进行工作。例如上面的printf。程序员可以自己写函数,或从库中调用函数。在上面的return 0;使得main返回一个值给调用程序的外壳,表明程序已经成功运行。

一个C语言的函数由返回值、函数名、参数列表(或void表示没有返回值)和函数体组成。函数体的语法和其它的复合的语句部分是一样的。

[]

复合语句

C语言中的复合语句(或称语句块)的格式为:

{语句;语句;……}

复合语句可以使得几个语句变成一个语句。

但一般情况下,我们不推荐这样多个语句顺序书写, 因为这样会使其可读性减弱,加大代码维护难度。

[]

条件语句

C语言有三种条件语句形式。两种是if,另一种是switch

两种if包括:

if (条件表达式)
语句;

以及

if (条件表达式)
语句;
else
语句;

在条件表达式中,任何非零的值表示条件为真;如果条件不满足,程序将跳过if后面的语句,直接执行if后面的语句。但是如果if后面有else,则当条件不成立时,程序跳到else处执行。

switch通常用于对几种有明确值的条件进行控制。它要求的条件值通常是整数或字符。与switch搭配的条件转移是case。使用case后面的标值,控制程序将跳到满足条件的case处一直往下执行,直到语句结束或遇到break。通常可以使用default把其它例外的情况包含进去。如果switch语句中的条件不成立,控制程序将跳到default处执行。switch是可以嵌套的。

switch (<表达式>) {
case <值1> :
<语句>
case <值2> :
<语句>
default :
<语句>
}

[]

循环语句

C语言有三种形式的循环语句:

do 
<语句>
while (<表达式>);
while (<表达式>) 
<语句>;
for (<表达式1> ; <表达式2> ; <表达式3>)
<语句>;

whiledo中,语句将执行到表达式的值为零时结束。在do...while语句中,循环体将至少被执行一次。这三种循环结构可以互相转化:

for (e1; e2; e3)
s;

相当于

e1;
while (e2) {
s;
e3;
}

当循环条件一直为真时,将产生死循环。

[]

跳转语句

跳转语句包括四种:goto,continue,break和return

goto语句是无条件转移语句:

goto 标记

标记必须在当前函数中定义,使用“标记:”的格式定义。程序将跳到标记处继续执行。由于goto容易产生阅读上的困难,所以应该尽量少用。

continue语句用在循环语句中,作用是结束当前一轮的循环,马上开始下一轮循环。

break语句用在循环语句或switch中,作用是结束当前循环,跳到循环体外继续执行。但是使用break只能跳出一层循环。在要跳出多重循环时,可以使用goto使得程序更为简洁。

当一个函数执行结束后要返回一个值时,使用returnreturn可以跟一个表达式或变量。如果return后面没有值,将执行不返回值。

[]

在C99中运算符号

+ - 
() [] -> . ! ++ -- (cast)  括号、成员、逻辑非、自加、自减、强制转换
++ -- * & ~ ! + - sizeof  单目运算符
* / % 算术运算符
算术运算符
<< >> 位运算符
< <= > >= 关系运算符
== != 关系运算符号
& 位与
^ 位异或
| 位或
&& 逻辑与
|| 逻辑或
 ?: 条件运算符
= += -= *= /= %= <<= >>= &= |= ^= 赋值运算符
, 顺序运算符
[]

数据类型

[]

基础数据类型

注意:以下是典型的数据位长和范围。但是编译器可能使用不同的数据位长和范围。这取决于使用的编译器。请参考具体的参考手册。

在头文件中说明了基础数据的长度。float,double和long double的范围就是在IEEE 754标准中提及的典型数据。

关键字 位长 范围
char 1 -128..127 or 0..255
unsigned char 1 0..255
signed char 1 -128..127
int 2 or 4 -32768..32767 or
-2147483648..2147483647
short int 2 -32768..32767
long int 4 -2147483648..2147483647
float 4 3.4x10-38E..3.4x10+38E
double 8 1.7x10-308E..1.7x10+308E
long double 12  ???
[]

数组

如果一个变量名后面跟着一个有数字的中括号,这个声明就是数组声明。字符串也是一种数组。它们以ASCII的NUL作为数组的结束。

例如:

int myvector [100];
char mystring [80];
float mymatrix [3] [2] = {2.0 , 10.0, 20.0, 123.0, 1.0, 1.0}
int notfull [3][3] = {{1},{1,2,3},{4,5}} (*)
char lexicon [10000] [300] ; /* 共一万个最大长度为300的字符数组。*/
int a[3][4];

上面最后一个例子创建了一个数组,但也可以把它看成是一个多维数组。注意数组的下标从0开始。这个数组的结构如下:

a[0][0] a[0][1] a[0][2] a[0][3]
a[1][0] a[1][1] a[1][2] a[1][3]
a[2][0] a[2][1] a[2][2] a[2][3]

例子(*)创建了一个3*3的二维数组,初始化时有些元素并未赋值.如下:

1 0 0
1 2 3
4 5 0

为0的位置的数值是随机的.

[]

指针

如果一个变量声明时在前面使用*号,表明这个变量是一个指针。换句话说,该变量是一个地址,而*则是取内容操作符,意思是取这个内存地址里存储的内 容。指针是C语言区别于其他同时代高级语言的主要特征之一。指针是一把双刃剑,许多操作可以通过指针自然的表达,但是不正确的或者过分的使用指针又会给程 序带来大量潜在的错误。

例如:

int *pi; /* 指向整型数据的指针 */
int *api[3]; /* 由指向整型数据的指针构成的数组,长度为3 */
char **argv; /* 指向一个字符指针的指针 */

储存在指针中的地址所指向的数值在程序中可以由*读取。例如,在第一个例子中,*pi是一个整型数据。这叫做引用一个指针。

另一个运算符&,叫做取地址运算符,它将返回一个变量、数组或函数的存储地址。因此,下面的例子:

int i, *pi; /* int and pointer to int */
pi = &i;

i和*pi在程序中可以相互交替使用,直到pi被改变成指向另一个变量的指针。

[]

字符串

要使用字符串并不需要引用库,但是C标准库确实包含了一些用于对字符串进行操作的函数,使得它们看起来就像字符串而不是数组。使用这些函数需要引用


  • strcat(dest, source) - 连接两个字符串,把source加到dest末尾。
  • strchr(s, c) -在字符串c中找出字符s第一次出现的位置。当没有找到时,返回Null。
  • strcmp(a, b) - 比较字符串ab的大小。如果两个字符串相同,返回0;如果a>b,返回正数;如果a,返回负数。
  • <- 把source中的n个字符追加到dest后面。null后面的值将不会被添加。
  • strncmp(a, b, n) - 比较字符串abn个字符的大小。如果两个字符串相同,返回0;如果a>b,返回正数;如果a,返回负数。
  • strncpy(dest, source, n) - 把字符串source拷贝到字符串dest中。(最多拷贝n个)
  • strrchr(s, c) - 在s中查找最后一次出现c的位置。返回这个位置。如果找不到,返回null。
[]

文件输入/输出

在C语言中,输入和输出是经由标准库中的一组函数来实现的。在ANSI/ISO C中,这些函数被定义在头文件中。

[]

标准输入/输出

有三个标准输入/输出是预定义的:

  • stdin 标准输入
  • stdout 标准输出
  • stderr 输入输出错误

这些定义在运行过程中是自动的打开和关闭的,所以它们并不需要进行显式定义。

下面的这个例子显示了一个过滤程序(filter program)是怎样构成的。

#include 
 
int main(){
int c;
while (( c = getchar()) != EOF ) {
if (anErrorOccurs) {
fputs("an error eee occurred\n", stderr);
break;
}
putchar(c);
}
}
[]

传递命令行参数

在命令行赋予程序的参数将通过在main()函数中定义一个整型参数(int)和一个指向字符指针的指针型参数(char **)来实现,前者传递命令行参数的个数,后者传递命令行参数内容。习惯上将这两个参数分别命名为argcargv。程序文件名被作为第一个命令行参数。

对于下列程序:

#include 
 
int main(int argc, char **argv) {
int i;
for(i=0;i printf("%d:%s\n",i,argv[i]);
return 0;
}

输入命令(假设该程序生成C:\TC\a.exe): a one two three

则会得到下面的输出结果:

0:C:\TC\A.EXE
1:one
2:two
3:three
[]

C语言的标准库

以下列出由C语言提供的标准函数库,函数库通过#include进行引用。

在C89标准中:

在95年的修正版中

在C99中增加了六个函数库

[]

C语言的保留关键字

char short int unsigned
long float double struct
union void enum signed
const volatile typedef auto
register static extern break
case continue default do
else for goto if
return switch while sizeof
阅读(851) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~