Chinaunix首页 | 论坛 | 博客
  • 博客访问: 397670
  • 博文数量: 158
  • 博客积分: 1227
  • 博客等级: 少尉
  • 技术积分: 946
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-20 16:19
文章分类
文章存档

2016年(1)

2015年(1)

2012年(107)

2011年(49)

分类:

2012-03-15 14:59:48

原文地址:C专家编程笔记 作者:landuochong

C专家编程笔记 开始日期:2010.8
/***************************************************************************/
date:0824
书签:66页,下一节:3.5 typedef
1.空格的妙用
m=*x/*y;这个语句编译会有问题,因为编译器将/*看成时注释,会认为这个语句没有结束,
解决方法:在/后面加上一个空格,即m=*x/ *y;即可。
2.变量类型强制转换为指向数组的指针
char (*str)[20]; //定义一个指向数组的指针(该例子可能有问题)
str=(char (*)[20])malloc(20);//申请一个具有20个char元素的内存单元
strcpy(*str,"help"); //注意这里是*str不是str,用str会有警告,但是这里总感觉有点问题
puts(*str);
free(*str);
str=NULL;
3.问题:这是什么?
int (* fun())();
int (*foo())[];
int (* foo[])();
char * const *(*next)();
char * const (*next)();
4.结构struct的申明
1)struct 结构标签(可选){
 类型1 标识符1;
 类型2 标识符2;
 ...
 类型3 标识符3;
}变量定义(可选);
例子:
struct date_tag{short dd,mm,yy;}my_birthday,xmas;
struct date_tag your_birthday,yman;
上面2种申明的my_birthday,xmas,your_birthday,yman都是相同的数据类型。
2)结构体中的位域和填充字段
例子:
struct kk
{
 int a:7;//一个int数据单元的前7位定义为a;
 int :9; //填充9个位,到达前面int数据单元的第7+9=16位;
 int b:10;//占据前面int数据单元的第17-27位;
 int c;
}a;
这个struct的大小是2个int大小,即8字节。
注意,一个位域变量只能位于一个数据类型单元里,上面的填充字节超过15则位域变量b只能存放于下一个int单元中。
位域变量和一般变量使用差不多,可以使用结构a.a=10来赋值,注意最大值不超过2^7=128。
5.不常用的枚举
例子:
enum test
{
 SUNDAY,     //注意枚举的每个元素前面没有类型定义,每个元素之间用逗号而不是分号(切记!)
 MONDAY,
 TUESDAY,
 WEDNESDAY,
 THURSDAY,
 FRIDAY,
 SATURDAY    //枚举的最后一个元素后面不需要逗号作为结束符
};
test22()
{
 printf("0[%d]-1[%d]-2[%d]\n",SUNDAY,MONDAY,TUESDAY);  //枚举使用时如果没有定义值,则初值从0开始。
}
6.C语言申明分析
6.1 char *const *(*next)();
分析:从标识符看起,
       (*next)   指向...的指针
看左右两边优先级,()优先级高于*,
        (     )() 该指针指向一个函数
        const *(     )()  该函数返回一个只读的指针
char *  const *(     )()  这个只读的指针指向一个char型指针
概括起来是:next是一个函数指针,该函数返回一个指针,该指针指向一个char型常量指针。
6.2 char *(* c[10])(int **p);
分析:从标识符看起,[]优先级高于*,
  c[10]   c是有10个元素的数组
      (*      )   每个元素都是指针
 看左右两边,右边()优先级高于左边*,
             (       )(int **p)  该指针指向一个函数
       char *(       )(int **p)  该函数返回一个char型指针
概括起来是:c是有10个元素的数组,每个元素都是一个函数指针,该指针指向的函数返回一个char型指针。
总结:申明分析就两点:一是从标识符看起,二是看左右运算符优先级,()和[]优先级都高于*.
/***************************************************************************/
date:0825
书签:82页,description.c分析
1.推荐一个C的调试函数assert,用于判断条件是否成立,不成立则马上退出程序并报错,显示assert的位置,比__FUNCTION__,__LINE__等更好用。
使用时需要加上头文件assert.h.
例子:
assert(0); 
printf("a");  //当assert检测到是0时不会执行下面的代码了,直接就退出了。
运行结果:
test: test.c:251: main: Assertion `0' failed.
Aborted
2.头文件中ifndef/define/endif结构的作用是防止头文件被重复引用。
3.#include 格式用来引用标准库的头文件,编译器将从标准库目录开始搜索,#include "filename.h"格式用来引用非标准库的头文件,编译器将从用户的工作目录开始搜索。
4.不要小看sizeof,会经常出错滴!
看招:
int i=-2;
if(i <= sizeof(int) -2)
 printf("A");
else
 printf("B");
结 果是哪一个呢?结果是输出B。为什么?先搞清楚,sizeof是个什么东东?sizeof是一个操作符,也就是和+、-等操作符一样,只不过作用是求一个 数据类型的内存占用字节数,但是注意它的结果是一个unsigned int,即是一个无符号数,在例子中,为了统一数据类型计算,i被转化为unsigned int是一个很大的数。
5.新函数:int isalnum(int c);
作用:判断字符变量c是否为数字或字母。
返回值:c为数字或字母则返回非0,否则返回0
例子:
char x='a';
printf("%c:%s\n",x,isalnum(x)?"yes":"no");  //结果为yes
char x='3';
printf("%c:%s\n",x,isalnum(x)?"yes":"no");  //结果为yes
char
;
printf("%c:%s\n",x,isalnum(x)?"yes":"no");  //结果为no
/***************************************************************************/
date:0927
1.声明和定义区别:定义只能出现一次,声明可以多次出现;定义相当于特殊的声明,它为对象分配内存,声明相当于普通的声明,它只是说明在其它地方创建了一个对象而不知道具体创建在哪里。
/***************************************************************************/
date:1101
1.#define 和typedef区别:#define只是简单的替换,而typedef是一种彻底的“封装”。
1.1 #define前面可以加关键词,而typedef不可以。
#define int apple   /*结尾不要分号*/
unsigned apple i;   /*没问题*/
typedef int peach;  /*结尾要分号*/
unsigned peach j;   /*错误*/
1.2 #define在连续的几个申明前面只对第一个有效,typedef对所有的都有效。
#define p_ts int *
p_ts p1,p2;    /*这里相当于 int *p1,p2 ,p2没有定义类型
nt a = 1;
int b = 2;
p1 = &a;
p2 = &b;      /*这一句会报警告*/
printf("a:%d,b:%d\n",*p1,*p2); /*编译出错*/
printf("a:%d,b:%d\n",*p1,*(int *)p2);  /*将p2强制转换就可以了,不过也会报警告*/
使用typedef就不会有以上问题了。
见PPT。
2.使用宏让strcmp看起来更舒服
#define STRCMP(a,R,b) (strcmp(a,b) R 0)
if(STRCMP(s, == , "hello"))  /* 相当于if(!strcmp(s,"hello")) */
3.指针和数组区别
指针存放数据的地址,数组存放数据;
指针通常用malloc,free赋值和释放,数组可以用str之类的函数赋值,系统自动释放;
指针通常指向匿名数据,数组名即数据;
字符串常量初始化的指针其字符串常量是只读的,字符串常量初始化的数组其字符串是可以更改的;
不可用浮点数初始化指针,即float * p = 123.45;编译有警告,运行会出错。
4.编译器怎样编译hello.c?
预编译 --> 语法和语义检查 --> 代码生成 --> 汇编 --> 优化 --> 链接,

preprocessor --> syntactic and semantic checker --> code generator --> assermbler --> optimizer -->linker
/***************************************************************************/
date:1102
1.编译生成的目标文件分段特点:
数据段保存在目标文件中,SS段不保存在目标文件中(除了记录BSS段在运行时所需的大小)。参考ppt中"变量在目标文件中的存放"。
/***************************************************************************/
date:1103
1.可执行文件运行和存放时的分段是不同的,存储态包括文本段、数据段、BSS段等,运行态包括文本段、数据段、BSS段和堆栈等。
相同点:文本段存放代码,数据段存放经过初始化的全局和静态变量,BSS存放未经过初始化的全局和静态变量。
不同点:存储态时没有堆栈,运行态时有有堆栈,主要存放局部变量,临时数据,函数参数和动态分配等。
参考PPT“可执行文件中的段在内存中的布局”和“使用共享库的运行态内存布局”。
/***************************************************************************/
date:1104
1.绝大多数的现代算法语言允许函数和数据一样在函数内部定义,但是C语言不允许用这种方法进行函数的嵌套。C语言中所有函数在语法上都是位于最顶层。
/***************************************************************************/
date:1105
1.linux编译器自带的调试工具
1.1源代码优化工具
 indent,作用:C程序美化器,优化布局和缩进格式。
使用方法: indent main.c
1.2可执行文件检查工具
 dump,作用:打印动态链接信息
使用方法:dump -Lv main.c 或者 dump -q mian.c
 ldd,作用:打印目标文件所需的动态库
使用方法:ldd a.out
 nm,作用:打印目标文件的符号表
使用方法:nm a.out
 
 strings,作用:查看嵌入二进制文件中的字符串。用于查看二进制文件可能产生的错误信息、内置文件名和(有时候)符号名或版本信息,使用方法 strings a.out。
 sum,作用:打印文件的校验和与程序块计数。
使用方法:sum a.out.
/***************************************************************************/
date:1201
1.字符串长度:从字符串首地址开始直到碰到'\0'为止的这一部分字符串长度。
例如:字符串"abc\0aaa"的长度是3,可以用strlen函数验证。
strlen()和sizeof()求字符串长度时区别:strlen计算实际赋值的字符串长度,sizeof计算字符串申请时的地址空间。
例如:
char a[20]="1234567890";
strlen(a)=10;
而sizeof(a)=20,即strlen计算的是字符串实际使用的空间大小,sizeof计算的是字符串申请的空间大小。
阅读(425) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~