C语言细节2OK

本文详细探讨了C语言中的关键概念,包括:x是否为2的若干次幂的判断、i++与++i的区别、静态局部变量的作用、关键字static和const的功能、内联函数与宏定义的差异、数据类型在不同编译器下占字节数的变化、数组和指针的区别、预定义头文件#include的使用规则、继承与组合的区别、new/delete与malloc/free的联系与区别。此外,还讨论了进程、线程和死锁的概念,以及Linux进程间通信的方式。文章适合C语言初学者和进阶者阅读,提供了丰富的示例和解释。
摘要由CSDN通过智能技术生成

代码实现题

P28 

P32 2.5.1 

P33 2.5.3

P34 2.5.4

P35 2.6.2

P36 2.6.3 

P37 2.6.5

P38 2.6.6

P48 2.9.1

P49 2.9.2  2.9.3

P53 2.9.4


第四章

P163 6.3.4 

P165 6.3.6

第七章

1,x是否为2的若干次幂

计算形参x转化为二进制后包含1的数量:

!x&(x-1)

2,i++ 和 ++i

i++是先用值i,然后等表达式(而非语句)运算完毕,再i+1;
++i是计算i+1,然后用值i+1代入表达式。
所以
int a = 1;
int b = 2;
cout<<(a++)>=(b++)?(a++):(b++)<<endl;//3
cout<<a<<" "<<b<<endl;//2 4


P32

http://blog.csdn.net/bingxuewujian/article/details/6728396

关于本段代码在VC++6.0中的规则如下: 
1、printf函数的执行顺序是由右到左的 
2、前自增运算符(++i)先加1,再使用i,此时i已经加了1; 
3、后自增运算符(i++)先使用i,再加1,***注意这里是关键所在,VC++6.0后自增运算是要在整条语句结束以后才自加1的!
所以: 
printf("%d,%d,%d,%d,\n",i++,++i,i,i++); 
从右往左运算: 
i++得到2(i=2,后加1在整条语句执行完才进行,这里先记下) 
i还是2 (i=2,原因见上一行) 
++i得到3(i=3,先加1,后使用) 
i++得到3(i=3,后加1在整条语句执行完才进行,这里先记下) 
所以输出结果为:3,3,2,2 
然后计算刚才的两次后自增运算后,i=5 

#include<stdio.h> 
void main() 
{ 
	int i=2; 
	printf("%d,%d,%d,%d,\n",i++,++i,i,i++); 
	printf("%d\n",i); 
} 

3,P34

float a = 1.0f;
cout << (int)a << endl;
cout << (int&)a << endl; 
cout << boolalpha << ( (int)a == (int&)a ) << endl; // (1)输出什么?

float b = 0.0f;
cout << (int)b << endl;
cout << (int&)b << endl;
cout << boolalpha << ( (int)b == (int&)b ) << endl;// (2)输出什么?

        输出结果是:
        1
        1065353216
        false
        0
        0
        true

      

 

答:(1)(2)分别输出false和true。注意转换的应用。(int)a实际上是以浮点数a为参数构造了一个整型数,该整数的值是1,(int&)a则是告诉编译器将a当作整数看(并没有做任何实质上的转换)。因为1以整数形式存放和以浮点形式存放其内存数据是不一样的,因此两者不等。对b的两种转换意义同上,但是0的整数形式和浮点形式其内存数据是一样的,因此在这种特殊情形下,两者相等(仅仅在数值意义上)。
注意,程序的输出会显示(int&)a=1065353216,这个值是怎么来的呢?前面已经说了,1以浮点数形式存放在内存中,按ieee754规定,其内容为0x0000803F(已考虑字节反序)。这也就是a这个变量所占据的内存单元的值。当(int&)a出现时,它相当于告诉它的上下文:“把这块地址当做整数看待!不要管它原来是什么。”这样,内容0x0000803F按整数解释,其值正好就是1065353216(十进制数)。
通过查看汇编代码可以证实“(int)a相当于重新构造了一个值等于a的整型数”之说,而(int&)的作用则仅仅是表达了一个类型信息,意义在于为cout<<及==选择正确的重载版本。


PS:(int&)是什么?

其实是一个别名的强制转换

 int &A=a;
引用即是一个变量的别名,例中A是a的一个别名,每一次访问A,对A的一系列操作实际上就是访问a,对a进行操作,此时的A和a在有些编译器中时同一个地址。在定义引用时必须初始化,且必须用有内存地址的对象初始化,初始化之后不可以在指向别的对象。


4,交换两个变量swap(a,b)

a = a + b;
b = a -  b;
a = a -  b;
或
a = a ^ b;
b = a ^ b;
a = a ^ b;
或
tmp = a;
a = b;
b = tmp;
或
a^= b^=a^=b;

但是对于异或来讲,如果做成函数的话,一定要判断传入的两个数相同:

void swap(int &a, int &b){
   if(a==b);
       return ;
    a^=b^=a^=b;
}
或者还可以利用编译器表达式从左到右计算(表达式计算顺序不由C语言规定,而是由编译器决定)

a = b + 0 * (b = a);

5,关键字static的作用

1)在函数体内,一个被声明为静态的变量在这一函数被调用过程中维持其值不变(该变量存放在静态变量区)。
2)在模块内(但在函数体外),一个被声明为静态的变量/函数可以被模块内所有函数访问,但不能被模块外其它函数访问。
3)static变量默认初始化为0。

int testStatic()
{
	int x=1;
	x++;
	return x;
}
main()
{
	int i;
	for(i=0;i<5;i++)
		printf("%dn",testStatic());
}
//输出为:2 2 2 2 2 
 
int testStatic()
{
	static int x=1;
	x++;
	return x;
}
main()
{
	int i;
	for(i=0;i<5;i++)
		printf("%dn",testStatic());
}
//输出为:2 3 4 5 6


把局部变量加上static 后改变了它的存储方式即改变了它的生存期,它在文件中只被初始化一次,下一次依据上一次结果值。例如:

int f(int i)  
{  
int a=0;  
static int c=1;  
cc=c+i;  
return c;  
}  
main()  
{  
printf("%d\n",f(1));  
printf("%d\n",f(1));  
//第二次对C 初始化已经无效,c 的值为上次执行结果的值  
} //2 3

5,静态局部变量

函数体内的static静态局部变量有以下特点:
1,该变量在全局数据区分配内存;
2,静态局部变量在程序执行到该对象的声明处时被首次初始化,即以后的函数调用不再进行初始化;
3,静态局部变量一般在声明处初始化,如果没有显式初始化,会被程序自动初始化为0;
4,它始终驻留在全局数据区,直到程序运行结束。但其作用域为局部作用域,当定义它的函数或语句块结束时,其作用域随之结束;


6,关键字const的作用

(1)可以定义 const 常量
(2)const可以修饰函数的参数、返回值,甚至函数的定义体。被const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。

[另],

如果const位于*的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;
如果const位于*的右侧,const就是修饰指针本身,即指针本身是常量。

const int a; //int型常量a
int const a; //含义同上
const int *a; //表示a是一个指针,指向一个int常量
int const* a;//含义同上
int * const a; //表示a是一个指针常量,指向一个int
int const * const a;//表示a是一个指针常量,指向一个int常量
const int* const a;//含义相同。


7,关键字const比宏定义#define的优点

1,const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而#define 只作简单的字符串替换,无类型安全检查。
2,const在编译时分配存储空间;而#define在预编译时编译,不分配存储空间。
3,有些集成化的调试工具可以对const进行调试,但不能对宏进行调试。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值