Something About Expert C Programming

原创 2016年05月30日 13:35:04
  1. 字符串的自动合并

int main( )
{
	char *Str[] = {"abc" "def"};
	printf( "%s\n", Str[0] );
	system("pause");
	return 0;
}

输出结果:abcdef

ANSI C规定相邻的两个字符串合并成一个字符串,必须注意在两个字符串之间添加“ ,”!但多余的“ ,”却并没有什么影响!


2.sizeof 的操作数

int main( )
{
	int b = 2;
	int *p = &b;
	int a = 3 *sizeof  *p;
	printf( "%d\n", a );
	system( "pause" );
	return 0;
}

输出结果:12

在上述程序中sizeof后面的操作数是(*p)所以是计算了 p指向的数据的数据类型的长度。

此处要注意运算符的优先级问题

tips: .高于* []高于* ()高于*  ==和!=高于位操作和赋值 算数高于移位 逗号的优先级最低


3.结合性

    1)所有赋值运算都具有右结合性  

int main( )
	{
		int a, b = 1, c = 2;
		a = b = c;
		printf( "%d\n", a );
		system( "pause" );
		return 0;
	}


    输出结果:2

    c赋值给b ,b赋值给c。


4.空格的误用

int main( )
{
	char a[] = "Hi,I am a\ 
		long string!";
	printf( "%d\n", a );
	system( "pause" );
	return 0;
}

此处在转义符的后面添加了空格,语法错误编译不能通过。这样的错误很难被发现,尽量避免!


5.最大一口策略

int main( )
{
	int a = 0;
	int b = 0;
	b = a+++3;
	printf( "%d,%d\n", b ,a);
	system( "pause" );
	return 0;
}

输出结果:3,1

结合性是a++ + 3

int main( )
{
	int *a = NULL;
	int *b = NULL;
	int c=*b/ *a;
	printf( "%d,%d\n", b ,a);
	system( "pause" );
	return 0;
}

在“/”和“*”之间必须有空格,不然编译器将后面的内容自动解析称为注释!


6.优先级规则分析案列

char *const *(*next)();

解释为:next是一个指向函数的指针,该函数的返回值是char *const


7.内存泄漏

内存泄漏:顾名思义,内存泄漏是由于我们使用了内存却没有收回造成的,

 这样的问题十分容易降低我们计算机的性能,并且泄漏的内存

 往往大于你忘记释放的数据的大小,因为malloc分配的内存通常

 会圆整为下一个大于申请数量的2的整数次方。

*同时,我们必须要避免内存损坏,即释放、改写仍在使用的内存。


8.段错误

1).解引用非法值的指针引起

	//引起一个段错误
	int main()
	{
		int *p=0;
		*p = 7; 
		system( "pause" );
		return 0;
	}

2).如果未初始化的指针恰好具有未对齐的值,会引起总线错误而不是段错误。

3).解引用一个空指针同样引起段错误(常常由于系统返回一个空指针而程序员不加判断直接使用造成)

4).用完了堆栈或者堆空间

引起段错误常见编程问题:1.坏指针值错误:在指针赋值之前就用它来引用内存或在释放之后仍然使用该指针

2.改写错误:越界写入数据

3.指针释放:多次释放或者释放一块不属于你的内存

注意:链表中元素的释放会经常引起此问题,我们必须用一个临时变量来保存下一次的地址才能够进行释放

9.类型转换

a.类型提升

        printf("%d\n",sizeof'A');

此程序的输出结果为4,在此char型自动被提升为int型。事实上计算机将char和short提升为整型,将float提升成double型

整型提升规则:每个变量的值被提升为int型的长度,然后对这些值进行计算,最后再对结果进行裁剪。

如果两个char型的加法运算结果没有溢出,那么在实际执行时只需要产生char类型的运算结果,可以省略提升。

	float f1,f2;
	double d;
	....
	f1 = f2*d;

如果编译器可以确定用float运算的结果和用double运算的结果相同,那么编译器也可以使用float类型运算。


C语言中的类型提升

char-->int 位段-->int 

enum-->int unsigned 

char-->int short-->int 

unsigned short-->int

float-->int 

任何数组-->相应类型的指针

float-->int 任何数组-->相应类型的指针

***参数也会进行提升,但是如果使用了函数原型,那么缺省的提升将不会发生!


10.有限状态机

有限状态机用于有限数量子程序的发展变化每个程序处理并选择下一个应该进入的状态

例如:注释转换

基本思路:用一张表来保存所可能的状态,并列出进入每个状态之后需要执行的动作,一般的最后一个动作用于决定你将要进入哪个状态。

我们可以通过函数指针数组来调用函数

	   extern int a() ,b(),c(),d();
	   int (*State[])()={a,b,c,d};
	   //可以通过调用数组中的指针来调用函数
	   (*State[i])();

当然,switch也是一个不错的实现机制


11.数组和指针的规则

a.“表达式中的数组名”相当于指针

b.C语言把数组的下标作为指针的偏移量

c.作为函数参数的数组名相当于指针

 关于这一点我们应该明白是出于对效率的考虑,类似的函数的返回值一定不能是一个数组,而是一个指向该数组的指针

Tips:为了保证一致性我们的定义和声明的形式必须保持一致

请尝试一下代码:

char ga[] = "abcdefghi";
void my_array( char ca[10] )
{
	printf( "数组的地址是:%#x \n",&ca);
	printf( "数组第一个元素的地址:%#x\n",&(ca[0]) );
	printf( "数组第二个元素的地址是:%#x\n",&(ca[1]) );
	printf( "++数组名得到的地址是:%#x\n",&(ca[1]) );
}
void my_pointer( char *pa )
{
	printf( "指针的地址是:%#x\n",&pa);
	printf( "指针偏移0的地址是:%#x\n", &(pa[0]) );
	printf( "指针偏移1的地址是:%#x\n", &(pa[1]) );
	printf( "++指针的地址是:%#x\n", ++pa );
}
int main( )
{
	printf( "全局变量数组的地址为:%#x\n",&ga );
	printf( "全局变量数组ga[0]的地址为:%#x\n", &(ga[0]) );
	printf( "全局变量数组ga[1]的地址为:%#x\n", &(ga[1]) );
	my_array( ga );
	my_pointer( ga );
	system( "pause" );
	return 0;
}

在输出的结果里我们发现:在函数里数组的地址和数组的第一个参数的地址不一样!

**在C语言中,我们无法向一个函数传递一个长度不确定的多维数组,你必须提供给它除了最左边一维以外所有的长度

在数组作为参数时:

1.一维数组 —— 需要包含一个计数值来方便我们检测是否越界访问

2.二维数组 —— 不能直接传递给函数,可以改成一个指向向量的指针数组来传参

        eg: char **myarray;

3.三维或更多维数组 —— 无法使用。必须将之分解成几个维度更小的数组。


本文出自 “Zimomo” 博客,请务必保留此出处http://zimomo.blog.51cto.com/10799874/1737231

版权声明:本文为博主原创文章,未经博主允许不得转载。

Expert Python Programming, 2nd Edition(读书笔记,似乎对Python 3.5并未着墨强调,但是代码示例容易看懂一点)

Expert Python Programming, 2nd Edition 目录 1 Python当前状态2 语法最佳实践:class级别以下3 语法最...
  • cteng
  • cteng
  • 2016年08月09日 13:41
  • 872

Expert Python Programming, 2nd Edition.pdf 英文原版 免费下载

下载地址:https://rejoice.ctfile.com/fs/1475340-229987341
  • jiongyi1
  • jiongyi1
  • 2017年12月05日 22:48
  • 70

【HDU 5984 Pocky】+ 数学

Pocky Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Total Su...
  • WYK1823376647
  • WYK1823376647
  • 2016年12月04日 21:37
  • 679

Expert C Programming读书笔记

下面所有内容均摘自Expert C programming一书   long int: The maximum value of long int cant be any less than 2,14...
  • imote
  • imote
  • 2004年07月12日 16:02
  • 1486

《Expert C Programming 》学习笔记

一、P19      将 char ** 类型 传给 const char **        1 foo(const char **p){ }  2  3 void main(int argc, c...
  • miyunhong
  • miyunhong
  • 2011年03月26日 20:59
  • 915

Something about C

What the hell? How long since I touch with C? What a pity, I have to work with it now.Pointer To ...
  • c602273091
  • c602273091
  • 2015年12月29日 17:56
  • 831

Expert C Programming

导致段错误的几个原因: 1) 解除引用一个包含非法值的指针    2) 解除引用一个空指针    3) 在未得到正确权限时进行访问,例如,试图在一个只读的文本段存储值就会引起段错误   4) ...
  • tkp2014
  • tkp2014
  • 2016年04月08日 16:53
  • 235

读《expert c programming》

“人人都知道调试比第一次写代码要难上一倍。所以如果在写代码时把自己的聪明才智发挥到极致,那么在调试时又该怎么办呢?” 《expert c programming》 真是一本不错的书,像小说一样剖析C语...
  • pingxu
  • pingxu
  • 2009年12月14日 13:30
  • 275

解决:ruby We're sorry, but something went wrong.We've been notified about this issue and we'll take a look at it shortly.

本人是ruby on rails 的初学者,前几天碰到了如上所示的问题,google了老半天,终于在一篇老外的博客上发现了问题,原来查看log目录下的development.log发现了问题所在“!/...
  • zhong871004
  • zhong871004
  • 2009年07月24日 15:57
  • 8729

《c expert programming》流水帐

p20556786889699122132146152163188190208230246262272chapter 1老套的c历史、c的标准输入输出库和预处理器、c标准语言的副本得到方法、较真的an...
  • laohaozi
  • laohaozi
  • 2007年06月10日 17:04
  • 577
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Something About Expert C Programming
举报原因:
原因补充:

(最多只允许输入30个字)