Expert C Programming读书笔记的详细介绍
Expert C Programming读书笔记的详细介绍
下面所有内容均摘自Expert C programming一书
long int:
The maximum value of long int can't be any less than 2,147,483,647(i.e., long integers are at least 32 bits).
long int的最大值不得小于2,147,483,647,也就是说,long型整数不得低于32位
Each argument should have a type such that its value may be assigned to an object with the unqualified version of the type of its correponding parameter.
每个参数都应该具有自己的类型,这样它的值就可以赋值给与它所对应的形参类型的对象。
This says that argument passing is supposed to behave like assignment.
这就是说参数传递过程类似于赋值。
ANSI C use value preserving approach.
ANSI C标准采用值保留原则。
When a signed int is comparing with unsinged int, the signed int is promoted to unsigned int.
当signed int与unsinged int做比较时,signed int被提升为unsigned int。
static:
Inside a function, retains its value between calls.
在函数内部,表示该变量的值在各个调用间一直保持延续性。
At the function level, visible only in this file.
在函数这一级,表示该函数只对本文件可见。
extern:
Applied to a function definition, hasglobal scope(and is redundant).
用于函数定义,表示全局可见,属于冗余。
Applied to a variable, defined elsewhere.
用于变量,表示它在其它地方定义。
void:
As the return type of a function, doesn't return a value.
作为函数的返回类型,表示不返回任何值。
In a pointer declaration, the type of a generic pointer.
在指针声明中,表示通用指针的类型。
In a parameter list, takes no parameters.
位于参数列表中,表示没有参数。
BSS segment:
It gets its name from abbreviating "Block Started by Symbol".
Local variables don't go in object file, but are created at runtime.
The test segment contains the program instructions.
The data segment contains the initialized global and static variables, complete with their assigned.
BSS段这个名字是“Block Started by Symbol”的缩写。局部变量不进入目标文件,它们在运行时创建。文本段包含程序的指令。数据段包含经过初始化的全局和静态变量以及他们的值。
Automatic variables are local varialbes declared inside funcitons.
自动变量就是定义在函数内部的局部变量。
Memory Leak
An addional point to note is that a leak will usually be larger than the size of the forgoten data structure, because malloc() usually rounds up a storage request to the next larger power-of-two.
另外需要注意的一点是,泄漏的内存往往比忘记释放的数据结构要大,因为malloc()所分配的内存通常会圆整为下一个申请数量的2的整数次方。
Alignment means that data items can only be stored at an address that is a multiple of their size.
对齐的意思就是数据项只能存储在地址是数据项大小的整数倍的内存位置上。
Common immediate causes of segmentation fault:
dereferencing a pointer that doesn't contain a valid value;
dereferencing a null pointer(often because the null pointer was returned from a system routine, and used without checking);
accessing something without the correct permission--for example, attempting to store a value into a read-only text segment would cause this error;
running out of stack or heap space(virtual memory is huge but not infinite).
通常导致段错误的几个直接原因:
解除引用一个包含非法值的指针;
解除引用一个空指针(常常由于从系统程序中返回空指针,但未经检查就使用);
在未得到正确的权限时进行访问。例如,试图往一个只读的文本段存储值就会引起段错误;
用完了堆栈或堆空间(虚拟内存虽然巨大但绝非无限)。
How to Free Elements in a Linked List:
struct node *p, *start, *tmp;
for(p=start; p; p=tmp)
{
tmp = p->next;
free(p);
}
Kbhit()
#include
#include
#include
#include
int kbhit(void)
{
int i;
ioctl(0, FIONREAD, &i);
return i;
}
void main(void)
{
int i = 0;
int c = ' ';
system("stty raw");
printf("enter 'q' to quit /n");
for(; c!='q'; i++)
{
if( kbhit() )
{
c = getchar();
printf("/n got %c, on iteration %d/n", c, i);
}
}
system("stty cooked");
return;
}
Rewriting the main function above to use curses instead of stty gives:
void main(void)
{
int i = 0;
int c = ' ';
initscr();
cbreak();
noecho();
mvprintw(0, 0, "Press 'q' to quit./n");
refresh();
while( c != 'q')
{
if( kbhit() )
{
c = getch();
mvprintw(1, 0, "got char '%c' on iteration %d. /n", c, ++i);
refresh();
}
}
nocbreak();
echo();
endwin();
return;
}
用FSM实现的声明分析器
#include
#include
#include
#include
#define MAXTOKENS 100
#define MAXTOKENLEN 64
enum type_tag {IDENTIFIER, QUALIFIER, TYPE};
struct token
{
char type;
char string[MAXTOKENLEN];
};
int top = -1;
struct token stack[MAXTOKENS];
struct token this;
#define pop stack[top--]
#define push(s) stack[++top] = s
enum type_tag classify_string(void)
{
char *s = this.string;
if (!strcmp(s, "const"))
{
strcpy(s, "read-only");
return QUALIFIER;
}
if (!strcmp(s, "volatile"))return QUALIFIER;
if (!strcmp(s, "void"))return TYPE;
if (!strcmp(s, "char"))return TYPE;
if (!strcmp(s, "signed"))return TYPE;
if (!strcmp(s, "unsigned"))return TYPE;
if (!strcmp(s, "short"))return TYPE;
if (!strcmp(s, "int"))return TYPE;
if (!strcmp(s, "long"))return TYPE;
if (!strcmp(s, "float"))return TYPE;
if (!strcmp(s, "double"))return TYPE;
if (!strcmp(s, "struct"))return TYPE;
if (!strcmp(s, "union"))return TYPE;
if (!strcmp(s, "enum"))return TYPE;
return IDENTIFIER;
}
void gettoken(void)
{
char
*p = this.string;
while((*p = getchar()) == ' ');
if(isalnum(*p))
{
while(isalnum(*++p = getchar()));
ungetc(*p, stdin);
*p = '/0';
this.type = classify_string();
return;
}
if(*p == '*')
{
strcpy(this.string, "pointer to");
this.type = '*';
return;
}
this.string[1] = '/0';
this.type = *p;
return;
}
void read_to_first_identifier(void)
{
gettoken();
while(this.type != IDENTIFIER)
{
push(this);
gettoken();
}
printf("%s is ", this.string);
gettoken();
}
void deal_with_arrays(void)
{
while(this.type == '[')
{
printf("array ");
gettoken();
if(isdigit(this.string[0]))
{
printf("0..%d ", atoi(this.string)-1);
gettoken();
}
gettoken();
printf("of ");
}
}
void deal_with_function_args(void)
{
while(this.type != ')')
{
gettoken();
}
gettoken();
printf("function returning ");
}
void deal_with_pointers(void)
{
while(stack[top].type == '*')
{
printf("%s ", stack[top].string);
}
}
void deal_with_declarator(void)
{
switch(this.type)
{
case '[':
deal_with_arrays();
break;
case '(':
deal_with_function_args();
break;
default:
break;
}
deal_with_pointers();
while(top >= 0)
{
if(stack[top].type == '(')
{
pop;
gettoken();
deal_with_declarator();
}
else
{
printf("%s ", stack[top].string);
}
}
}
int main(void)
{
read_to_first_identifier();
deal_with_declarator();
printf("/n");
return 0;
}
When Arrays Are Pointers
The C standard has the following to say about the matter:
1. An array name in expression (in contrast with a declaration) is treated by the compiler as a pointer to the first element of the array.
2. A subscript is always equivalent to an offset from a pointer.
3. An array name in the declaration of a function parameter is treated by the complier as a pointer to the first element of the array.
什么时候数组和指针是相同的
C语言标准对此作了如下说明:
规则1. 表达式中的数组名(与声明不同)被编译器当作一个指向该数组第一个元素的指针;
规则2. 下标总是与指针的偏移量相同;
规则3. 在函数参数的声明中,数组名被编译器当作指向该数组第一个元素的指针。
The compiler take care of scaling before adding in the base address. This is the reason why pointers are always typed - constrained to point to objects of only one type - so that the compiler knows how many bytes to retrieve on a pointer dereference, and it knows by how much to scale a subscript.
对起始地址执行加法操作之前,编译器会负责计算每次增加的步长。这就是为什么指针总是有类型限制,每个指针只能指向一种类型的原因所在-因为编译器需要知道指针进行解除引用操作时应该取几个字节,以及每个下标的步长应取几个字节。
The array/pointer equivalence for parameters was done for efficiency. All non_array data argument in C are passed "by value" (a copy of the argument is made and passed to the called function; the function can't change the value of the actual variable used as an argument, just the value of the copy it has).
把作为形参的数组和指针等同起来是出于效率原因的考虑。在C语言中,所有非数组形式的数据实参均以传值形式(对实参作一份拷贝并传递给调用的函数,函数不能修改作为实参的实际变量的值,而只能修改传递给它的那份拷贝)调用。
Arrays and Pointers Interchangeability Summary:
1. An array access a[i] is always "rewritten" or interpreted by the compiler as a pointer access *(a+i);
2. Pointers are always pointers; they are never rewritten to arrays. You can apply a subscript to a pointer; You typically do this when the pointer is a function argument, and you know that you will be passing an array in.
3. An array declaration in the specific context (only) of a function parameter can equally be written as a pointer. An array that is a function argument (i.e., in a call to the function) is always changed, by the compiler, to a pointer to the start of the array.
4. Therefore, you have the choice of defining a function parameter with is an array, either as an array or as a pointer. Whichever way you define it, you actually get a pointer inside the function.
5. In all other cases, definitions should match declarations. If you define it as an array, you extern declaration should be an array. And likewise for a pointer.
数组和指针可交换性的总结
1.用a[i]这样的形式对数组进行访问总是被编译器“改写”或解释为象*(a+i)这样的指针访问。
2.指针始终都是指针。它绝不可以改写成数组。你可以用下标形式访问指针,一般都是指针作为函数参数时,而且你知道实际传递给函数的是一个数组。
3.在特定的上下文中,也就是它作为函数的参数(也只有这种情况),一个数组的声明可以看作是一个指针。作为函数参数的数组(就是在一个函数调用中)始终会被编译器修改成为指向数组第一个元素的指针。
4.因此,当把一个数组定义为函数的参数时,可以选择把它定义为数组,也可以定义为指针。不管选择哪种方法,在函数内部事实上获得的都是一个指针。
5.在其他所有情况中,定义和声明必须匹配。如果定义了一个数组,在其他文件对它进行声明时也必须把它声明为数组,指针也是如此。
Notice how the initialization is identical to the arrays of characters initialization. Only string literals have this privilege of initializing pointer arrays. Arrays of pointers can't be directly initialized with non-string types.
注意指针数组的初始化部分与字符“数组的数组”初始化部分是一样的。只有字符串常量才可以初始化指针数组。指针数组不能由非字符串的类型直接初始化。