现在的位置: 首页 > 综合 > 正文

C 专家编程 笔记(一、二、三章)

2013年10月25日 ⁄ 综合 ⁄ 共 4140字 ⁄ 字号 评论关闭

1.编辑器设计者的金科玉律:效率(几乎)就是一切

2.阅读ANSIC标准 , 寻找乐趣和裨益

具体的ANSI C标准的规定我都不说了,从中看出 char * 类型是可以作为参数专递的,但是char** 是不行的,所以我们

传递多维数组的时候要表明确前n-1维的下标

3.容易混乱的const

int main(int argc, char* argv[])
{

	//定义基本类型的const变量,const 位置在哪儿都可以
	const int x = 2,y = 3;  //两个常量

	//定义一个非const变量
	int z = 3;     //一个普通变量

	//定义一个指向常的指针
	const int* pc = &x;   //指向常量的指针

	//定义一个常指针
	int* const cp = &z;   //常指针
	
	//定义一个非const指针
	int* pp = &z;    //int 型指针

	pc = &z; //可以,pc是一个指向常量的指针,不能通过该指针去修改指针所指向的内存空间的值,但是,该指针可以指向别的变量

	// *pc = 10; //不可以,*pc所指向的地址为const变量,其值不可更改 pc是一个指向常量的指针,不能通过该指针去修改指针所指向的内存空间的值

	pc = pp; //可以,pc为指针,其值可被改变 pc是一个指向常量的指针,pp是一个普通指针,用一个普通指针给一个指向常量的指针赋值是可以的
	// pp = pc; //用一个指向常量的指针,赋值给一个普通指针,不可以。如果可以,那么就可以通过普通的指针去修改内存的值

	*cp = x; //可以,通过常指针去修改指针所指向变量的值是可以的

	// cp = &x; //不可以,cp为常指针,指针的值不能被修改,给常指针赋值是错误的

	// pp = &x; //不可以,pp是非const指针,原则上来讲给它赋值是可以的,在不同的编译器下有不同的结果
	// pp = pc; //不可以,指向常量的指针不能赋值给一个普通的指针
	pp = cp; //可以,常指针可以赋值给一个普通指针

	const int * const pp = &a; //双const 既保护指针又保护内存变量

	return 0;
}

4.ASINC 手册重新编写了有关内容整型升级和寻常算数转换

注意:  #define  TOTAL_ELEMENTS       ( int )( sizeof(array)  /  sizeof(array[0]) )  必须加上(int)强制转换,不然运算的结果是个  unsigned int  类型,在程序中与有符号数运算时会发生意想不到结果


5. 错误断言

无论什么时候遇见  malloc(strlen(str))   都是错误的

而 malloc(strlen(str) + 1) 是正确的

因为字符串处理包含了一个额外的空间,用于容纳字符串结尾的‘\0’


6. 一个‘L’的NUL  和  两个 ‘L’的NULL


7. switch 中case  后面不用break   97%都是错误的,而且default这单词如果写错的话,编译器是不检测的。

8. 在字符串数组在初始化的时候,如果不小心漏掉了一个逗号,编译器不会发出错误信息,而是悄无声息地把两个字符串合起来

#include<stdio.h>
#include<string.h>

#define  TOTAL_ELEMENTS    (int)(sizeof(str)/sizeof(str[0]))

int main()
{
	char *str[] = {
		"aaa",
		"bbb",
		"ccc",
		"ddd"
		"eee",
	};
	printf("the length of the array is %d\n",TOTAL_ELEMENTS);
	for(int i = 0; i < TOTAL_ELEMENTS; i++)
		puts(str[i]);
	return 1;
}

结果:

9. 使一段代码第一次执行的行为与以后执行时间不同(函数中申请静态变量)


10. i = 1, 2; 的结果是i 为多少呢?

赋值运算符的优先级高于逗号,所以 实际情况为:  (i  = 1), 2 , 所以i 最终的值为1

而 i = (1 ,2);的结果i 为2;

 

11.计算的次序

 

 12 理解C的优先级规则

13 typedef 一些用法

 

 

14 typedef int x[10] 和 #define x  int[10]的区别

 a.用其他类型对宏类型名进行扩展,但typedef所定义类型名不能

    #define  peach  int 

    unsigned peach i; //  /* 没问题 */

    typedef  int  banana

    unsigned banana i; /*错误! 非法*/

b. 连续几个变量的声明中,用typedef定义的类型能够保证声明中所有的变量均为同一类型,而用#define定义的类型则无法保证.

    #define  int_ptr  int *;

   int_ptr  chalk,  cheese;

  经过宏展开,变为   int *  chalk , chese;// 发现chalk  和  chese 不是同一类型。

 

15

 

根据上面的思路写的解析声明的算法

#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<stdlib.h>

#define MAXTOKENS 100
#define MAXTOKENLEN 64

enum type_tay {	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_tay classify_string() /*判断标示符类型*/
{
	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() /* 读取下一个标记到 "this" */
{
	char *p = this.string;
	
	/*略过空白字符*/
	while((*p = getchar()) == ' ');
	
	if(isalnum(*p))/* 读入的标示符A-Z,0-9*/
	{
		while(isalnum(*++p = getchar()));
		ungetc(*p,stdin);
		*p = '\0';
		this.type = classify_string();
		return;	
	}		
	
	if(*p == '*')
	{
		strcpy(this.string, "pionter to");
		this.type = '*';
		return;
	}
	this.string[1] = '\0';
	this.type = *p;
	return;
} 
 
 /*理解所有分析过程的代码*/
void read_to_first_identifier()
{
 	gettoken();
 	while(this.type != IDENTIFIER)
 	{
		push(this);
		gettoken(); 	
    }
    printf("%s is ", this.string);
    gettoken();
} 
 
void deal_with_arrays()
{
 	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()
{
	while(this.type != ')')
	{
		gettoken();
	}
	gettoken();
	printf("function returning ");
} 

void deal_with_pointers()
{
	while(stack[top].type == '*')
	{
		printf("%s ",pop.string);
	}
}

void deal_with_declarator()
{
	/*处理标识符之后可能存在的数组/函数*/
	switch(this.type)
	{
		case '[': deal_with_arrays(); break;
		case '(': deal_with_function_args();break;
	} 
	
	deal_with_pointers();
	
	/*处理在读入到标识符之前压入到堆栈中的符号*/
	while(top >= 0)
	{
		if(stack[top].type == '(')
		{
			pop;
			gettoken(); /* 读取')'之后的符号 */ 
			deal_with_declarator();
		}
		else
		{
			printf("%s ",pop.string);
		}
	}
}
 
 
int main()
{
	/* 将标记压入堆栈中, 知道遇到标示符*/
	read_to_first_identifier();
	deal_with_declarator();
	printf("\n");
	return 0; 
}

 

抱歉!评论已关闭.