ANSI C学习笔记

发布于 25 天前  421 次阅读


Formatted Output

在C语言中,"流"是一个抽象概念。从程序的角度来看,它只是一个字节的生产者(输入流)或消费者(输出流)。它可以对应于磁盘上的一个文件、一个管道或终端,或者其他一些设备,如打印机。

有三个标准流:stdin是一个指向标准流的指针,stdout是一个指向标准输出流的指针,stderr是一个指向标准错误输出流的指针。FILE类型包含关于流的信息。通常情况下,不会直接处理FILE对象的内容,只是把它的一个指针传递给各种I/O例程。

fprintf将格式化的文本写到指定的输出流中。
printf相当于写fprintf(stdout,…),将格式化的文本写到标准输出流当前指向的地方。
sprintf将格式化的文本写到一个char数组中,而不是一个流。

Variables

char类型实际上是整数类型,长度是8 bits,范围是-128到127;unsigned char范围是0到255。

typedef在语法上和staticextern关键字位置一样,作用是给现有的数据类型一个新的名字或者定义一个新的数据类型。在C++中,typedef不常用,只用enum也可定义新的数据类型。

函数中的static类型变量在函数结束后不被清除,而是保留其值。static全局变量或函数限定了其范围,即不可以被其他源文件获得。

violatile表示用于存储对象的字节可能会被与程序平行运行的其他东西改变或访问。这对程序的影响是,编译器对内存的访问进行特殊处理。如果你访问它两次,编译器不会缓存第一次访问,并且两次使用相同的值,而是进入内存硬件并执行两次读操作。而当修改对象时,该修改会被立即写入,并且完全按照指定,没有缓冲或重新排序的优化。

引用头文件相当于复制头文件中的内容,如果一个头文件被引用两次,编译器会处理两次头文件,这会产生错误。为了防止这种做法,把文件的整个内容放在条件编译语句中。

#ifndef HEADER_FILE
#define HEADER_FILE
// the entire header file
#endif

  • include< >和include" "的区别
    include< >引用的是编译器的类库路径里面的头文件。
    include" "引用的是程序目录的相对路径中的头文件。

Pointers and Arrays

取地址运算符&和解引用运算符*与累加运算符++和递减运算符--有同样的优先级,同时出现时,按照从右到左的顺序解释,即*p++==*(p++)为真。

malloc()函数原型是void* malloc(unsigned size),功能是在堆内存中分配一块长度为size字节的连续内存空间,不会初始化所分配的空间。
calloc()函数原型是void* calloc(size_t num, size_t sizeof),功能是在内存中申请num*sizeof字节的连续内存空间,会将所分配空间的每一位初始化为0。

realloc()函数原型是void* realloc(void* ptr, unsigned newsize),功能是为ptr重新分配newsize字节的连续内存空间。
ptr进行判断:
如果ptr为NULL,则函数相当于malloc(new_size),分配一块大小为new_size的内存,如果成功,则返回地址,否则返回NULL。
如果ptr不为NULL,则查看ptr是不是在堆中,如果不是,抛出realloc invalid pointer异常。如果ptr在堆中,则查看newsize大小,如果newsize大小为0,则相当于free(ptr),返回NULL。如果newsize大于原大小,则查看ptr指向的位置还有没有足够的连续内存空间,如果有的话,分配更多的空间,返回的地址和ptr相同,如果没有的话,在更大的空间内查找,如果找到newsize大小的空间,将旧的内容拷贝到新的内存中,把旧的内存释放掉,返回新地址。

[]*优先级高。short a[10][20]表示10个20元素数组;short *b[10]表示10个short指针;short (*c)[20]表示1个指向20元素数组的指针。

Multi-dimensional Arrays

有三种方式可以建立一个10x20的多维数组:

1. 200个连续的short变量

const short a[MAX_ROWS][MAX_COLS] = { {...},{...} };

这种情况需要的内存空间是200 x sizeof(short)。

2. 10个连续的short指针

for (i = 0; i < 10; i++){
b[i] = (short* ) malloc (sizeof (short) * 20);}

之后可以用(b[i])[j]访问元素。这种情况需要的内存空间是(10 x sizeof(short*)) + (10 x 20 x sizeof(short))。

3. 1个指向20元素数组的指针

typedef short (*PointerToArray) [20];
c = (PointerToArray) malloc (sizeof (short) * 20 * 10);

之后可以用c[i][j]访问元素。这种情况需要的内存空间是sizeof(short*) + (200 x sizeof(short))。

Function Pointers

返回值是int的指针的函数:
int* f (void);

返回值是int的函数的指针:
int (*f) (void);

Structures

声明一个没有赋值的structure后,系统并不为其分配内存空间,它只是定义了模板供以后使用。

运算符.比*的优先级高:*pp.x==*(pp.x)为真。

数据结构对齐:
CPU在数据自然对齐时能最有效地执行对内存的读写,所以数据的内存地址通常是是数据大小的倍数。例如,在32位机器上,一个包含16位值和32位值的structure可以在16位值和32位值之间有16位的填充,以使32位值在边界上对齐。
struct{char c; long l;} x;
struct{long l; char c;} y;
sizeof(x) == 8;
sizeof(y) == 5;

structure可以递归,但是必须以指针形式,因为编译器无法为 正在被解析的 structure类型的 成员分配内存。而指针的大小是已知的。

Unions

unions允许在同一内存位置存储不同的数据类型。可以定义具有许多成员的unions,但在任何给定时间只有一个成员可以包含值。unions将同一内存位置用于多种用途。

union optionalTag
{ short s; char c; long l; } u;

类似于structure,用运算符.和->指示成员。

Bit Fields

为了更好地利用内存空间,C语言可以预定义变量宽度,即占用bits的数量,这样的变量叫bit fields。

例如
struct
{
unsigned int widthValidated : 1;
unsigned int heightValidated : 1;
} status;

在32位机器中,status占用4个字节的空间,其中2位被利用。

如果不使用位域,即
struct
{
unsigned int widthValidated;
unsigned int heightValidated;
} status;

则status占用8个字节的空间。

位域只能被声明为(unsigned) ints,且每个位域不能单独寻址。

虽然ANSI C在语法上定义了位域,但是其实现完全取决于机器。例如
struct{
unsigned int mute : 1;
unsigned int backlight : 1;
unsigned int unused : 14;
} bits;
bits.mute = 1;
值为1的bit不一定位于bits内存空间的第一位,也可能位于最后一位。


Humble Halten