Android Tech And Thoughts.

C Language Tutorial

Word count: 2kReading time: 8 min
2019/12/10 Share

译者注:这是一份C指南,目的在于指导C初学者快速开始并了解C语言,其并不能代替市面上大多数的教材。这里推荐一本非常著名且优秀的C语言教材:

The C Programming Language –ANSI C

–By Brian W.C. Kernighan & M. Ritchies

大纲:

  1. 第一个程序
  2. 计算
  3. 循环
  4. 宏常量
  5. 条件语句
  6. 指针
  7. 数组
  8. 字符数组
  9. I/O功能
  10. 函数
  11. 命令行参数
  12. 图形接口

1. A First Program

1
#include<stdio.h>
2
3
void main(){
4
	printf("\nHello world\n");
5
}

将代码保存在 hello.c 中,然后输入下面的命令进行编译:

1
gcc hello.c

这将产生一个可执行文件 “a.out”
一个C程序包含 函数 与 变量,函数指明了程序需要完成的任务,”main” 函数建立了所有的程序逻辑,通常我们需要保证他是简洁的(通过调用其它的函数来运行子逻辑),所有的 C 程序都有且只有一个 “main” 函数。

printf是来自于 I/O 函数库 (defined in stdio.h), 最原始的C语言并没有内置的 I/O 库,这些都是后来发展中新增的并最终并入了 ANSI C 规范中。 The K & R 教科书列出了这些新增的标准库

2. Let’s Compute

下面的程序 ,”sine.c” ,计算了从 0 到 360 度的角度的 sine 函数值

1
#include <stdio.h>
2
#include <math.h>
3
4
void main(){
5
	int angle_degree;
6
  double angle_radian,pi,value;
7
  
8
  printf("\nCompute a table of the sine function\n\n");
9
  
10
  // atan 是反正切函数
11
  pi = 4.0*atan(1.0);
12
  printf("Value of PI = %f \n\n",pi);
13
  printf("angle Sine \n");
14
  angle_degree = 0;
15
  
16
  while(angle_degree<=360){
17
  	angle_radian = pi*angle_degree/180.0;
18
  	value = sin(angle);
19
  	printf("%3d  %f \n",angle_degree,value);
20
  	
21
  	angle_degree = angle_degree+10; /*increament the loop index */
22
  }
23
}

这个函数同样包含了一些定义于 math 函数库的函数

变量名的命名是随意的(部分编译器规定了最大长度,典型的是32个字符), C 使用以下标准的变量类型:

1
int 
2
short
3
long
4
float
5
double
6
char

// 有点奇怪,C里面没有 byte 和 boolean 么

printf(“format”,var) 格式问题:

1
%.nd		integer n位表示,不足用0补齐
2
%m.nf   
3
%ns 		string(optional n=number of columns)
4
%c			character
5
\n \t		to introduce new line or tab
6
\g			ring the bell(‘beep') on the terminal

Loops

大多数现实中的小恒徐会包含一些循环结构在程序里面。针对一些连续的数据或内存,执行一些相对固定的逻辑。在C程序中,实现循环有多种方式,最常见的就是 while 循环和 loop 循环。

1
while(expression){ //expression为true则进入循环体
2
	...block of statements to execute...
3
}
4
5
for(expression_1;expression_2;expression_3){ //expression_2为true则进入循环体
6
	...block of statements to execute...
7
}

无限循环是被允许的,通常用break关键字跳出循环,例如:

1
angle_degree = 0;
2
for(;;){
3
	...blocks of statements...
4
	
5
	angle_degree = angle_degree+10;
6
	if(angle_degree==360)break;
7
}

//TODO:空表达式是真值?

Symbolic Constants

你可以通过 编译指令 #define 定义任何类型的常量

1
#define ANGLE_MIN 0
2
#defind ANGLE_MAX 360

Conditionals

1
if(conditional_1){
2
	...block of statements executed if conditional_1 is true...
3
}else if(conditional_2){
4
	...block of statements.....
5
}else{
6
	...
7
}
8
9
switch(expression){
10
	case const_expression_1:
11
	{
12
		...
13
		break;
14
	}
15
	case const_expression_2:
16
	{
17
		...
18
		break;
19
	}
20
	default:
21
	{
22
		...block of statements...
23
	}
24
}

注意switch语句的执行流程,是从上到下,如果某个分支没有break,会继续执行下一条分支

1
&&		and
2
||		or
3
!			not

Pointers

啊哈,重头戏指针:C语言允许程序员对内存直接进行操作,这个特性给予了语言无情的灵活性和力量,但是,这也是非常巨大的障碍,初学者必须克服以便于能正确高效地运用C语言。

程序中的所有变量都保存在内存之中

1
float x;
2
x = 6.5;

这段代码为float变量x请求4个字节的内存,并把6.5写入其中。有时候我们需要了解变量在内存中存储的位置,”&”操作符提供了这个功能,将 “&” 置于变量名var前面,就代表了var的地址:

1
float x;
2
x = 6.5;
3
&x;

C语言同时提供了一种类型的变量,来存储地址类型,这个变量就是指针变量。

1
float* px;
2
px = &x;

“*” 的理解有两个方面,我们且看下面的两种表现形式

1
float* x;
2
float *x;

float* 表示一个float型指针(地址类型)
而 float x 则表示 *x是一个float变量,在这种意义下表示的就是该x地址所指向的内容的值,很多书本上,将地址变量比喻成门牌号,我觉得是很贴切的,给地址变量前面加个 * 就表示了门牌号所指代的房间(内容)。实际上上面两种形式下,x 的含义也是不变的,都是一个地址变量。

可以叠加,例如 “float* p”,p则为描述地址的地址。

地址类型之间也可以强转,强转之后,指针的地址虽未改变,其内容(内存角度)也为改变,但其内容所代表的变量类型却改变了。看下面这个例子:

1
char* pc;
2
float* px;
3
float x;
4
5
x=6.5;
6
px = &x;
7
pc = (char*) px;  //this is a cast

pc和px指向同一地址吗,但 px+1 与 pc+1 则指向不同的内存地址

Arrays

通用的声明格式如下:

1
type name[dim];

Struct

Array是一组相同类型数据的集合,只是有时候我们也需要不同类型数据的集合,从设计思想上,二者也有不同,Array是方便进行批处理,而Struct则是将相关联的数据联系起来,进行同步处理,Struct优点类似类的概念。

Struct的一般结构如下:

1
struct 结构体名{
2
	结构体所包含的变量或者数组或者结构体变量
3
}

结构体也是一种数据类型,它由程序员自己定义,可以包含多个类型的数据。像 int 、float、char 等是C语言本身提供的数据类型,不能进行再拆分。我们称之为基本数据类型,而结构体则属于复杂数据类型或者构造数据类型

结构体变量

1
struct stu{
2
	char *name;
3
	int  schoolNum;
4
	int  age;
5
	float score;
6
}stu0;  //变量可以直接放在结构体定义的最后
7
8
struct stu stu1,stu2;

理论上讲,结构体的各个成员再内存中是连续存储的,和数组非常相似。但是再编译器的具体实现中,各个成员之间可能存在缝隙,这是为了内存对齐,提高寻址效率。

结构体变量使用 . 来获取单个成员

1
int age = stu1.age;
2
float score = stu1.score;

除了可以对成员进行逐一赋值,也可以在定义时整体赋值,例如:

1
stu stu1 = {"Tom","20092510",18,90f};

->操作符

->操作符和 . 操作符都是对结构体内的数据进行访问。不同的是, ->操作符是一个指向结构体的指针对该结构体中的数据进行访问

1
stu *stu;
2
stu.name = "YUDAN";
3
4
char *str = stu->name;

C语言中的变量与Java中的变量有什么不同

Java中的变量有很多种,对于基本类型的变量而言,二者是相同的,其实它们都是一个地址,指向存储的数据
对象变量当然也是一个地址(或者说引用),只是它作为一个地址指向的是一个存储在堆中的对象。而普通的基本类型变量又分为局部变量或者对象变量,二者的作用域不同,存储的区域自然也不同,后者是线程私有的,存储在线程的栈帧中,前者则存储在对象之中,作为对象的一部分。

CATALOG
  1. 1. 1. A First Program
  2. 2. 2. Let’s Compute
  3. 3. Loops
  4. 4. Symbolic Constants
  5. 5. Conditionals
  6. 6. Pointers
  7. 7. Arrays
  8. 8. Struct
  9. 9. ->操作符
  10. 10. C语言中的变量与Java中的变量有什么不同