Date:2013-02-03
1.数组名不可以左值操作,但是..
在segmentfault看到了一个问题.
代码如下:
#include <stdio.h> main(int argc, char const* argv[]) { char const* arr[]={"Hello","World","AndyXue"}; *++argv; *++arr; }
运行结果
1.c: In function ‘main’: 1.c:6:6: error: lvalue required as increment operand
也就是:argv允许自增, 但是arr不可以 .
数组名是不可以做自增运算的, 但此处为何指针数组名argv可以自增呢?
因为, C语言中数组传入函数作为参数都是传的数组地址.此处argv只被认为成一个二维指针.
2.C不生成临时变量交换变量的值
两个方法:
#include <stdio.h> int main(int argc, const char *argv[]) { int a=1,b=2; a ^= b ^= a ^= b; printf( "%d%d", a, b ); return 0; }
#include <stdio.h> int main(int argc, const char *argv[]) { int a=1,b=2; a=a+b; b=a-b; a=a-b; printf( "%d%d", a, b ); return 0; }
3.数组名和数组下标可以互换
这个是老生常谈的了.以下代码可以顺利通过编译
#include <stdio.h> int main(int argc, const char *argv[]) { char arr[]="abcdef"; printf( "%c",2[arr]); return 0; }
因为a[b]被认为成*(a+b).所以2[arr]也是可以的.但是对于可读性没有好处
4. http:
#include <stdio.h> int main() { http://www.shello.name/ printf("haha!!\n"); return 0; }
解释如下:
双斜杠之后是注释掉的.前面http:相当于一个goto的标签
5.sizeof不是一个函数
#include <stdio.h> main() { int i = 0; sizeof(i++); printf("%d\n", i); }
这里打印结果是0.i并没有自增.这说明sizeof不是个函数.
sizeof不是一个函数,而是一个操作符,求i++的类型的size,这是一件可以在程序运行前(编译时)就确定的事情,所以,sizeof(i++)直接就被4给取代了,在运行时也就不会有了i++这个表达式
6. 数组类型强制转换
#include <stdio.h> int main(int argc, const char *argv[]) { printf( "%d", ((int[]){1,2,3,4})[1] ); return 0; }
把{1,2,3,4}强转成int[]形,再取数组{1,2,3,4}的下标为1的数
7.结构体对齐
#include <stdio.h> int main(int argc, const char *argv[]) { struct foo1{ char c1; int i; char c2; }; struct foo2{ int i; char c1; char c2; }; printf("%d %d\n",sizeof(struct foo1),sizeof(struct foo2)); return 0; }
执行结果是12 8
因为C中采用对齐的方式存储结构体.
foo1中是这么存储的: c1 (跟int i对齐,由1扩展为4) i sizeof取值得4 c2 (跟int i对齐,由1扩展为4) --------------------------------------------------------------- foo2中是这么存储的: i sizeof取值得4 c1,c2连续存储,并由2扩展为4,跟int i对齐
你可以给foo2这么写:
struct foo2{ int i; char c1; char c2; char c3; };
再编译执行下会发现结果不变, 大小还是8.这说明对齐确实存在.再追加一个c4,foo2大小还是为8
8.function(void)与function()的区别
看下面代码的编译结果
void foo1(){} void foo2(void){} main() { foo1(1); foo2(1); }
编译:
1.c: In function ‘main’: 1.c:6:2: error: too many arguments to function ‘foo2’ 1.c:2:6: note: declared here
function(void)是严格的表示它没有参数
function()是指参数类型未知
9.宏中的#号
#define h(a) printf(#a"\n"); main(){h(abc)}
#:在宏展开的时候会将#后面的参数替换成字符串
##:将前后两个的单词拼接在一起
#@:将值序列变为一个字符
10.main(x)中的x
#include <stdio.h> int main(x) { printf("%d", x); return 0; }
打印的是c文件接收到的参数的个数
11.编译的时候再输入C代码
写一个一行C程序1.c:
#include "/dev/tty"
然后编译它:
cc 1.c -o 1
会发现在编译的时候可以输入.那么我们输入一段c代码:
int main(){ printf("hello"); return 0; }
按下Ctrl-D结束输入
测试结果 :
$ cc 1.c -o 1 int main() { printf("hello"); return 0; } In file included from 1.c:1:0: /dev/tty: In function ‘main’: /dev/tty:3:5: warning: incompatible implicit declaration of built-in function ‘printf’ [enabled by default] $./1 hello$
同样的还有
#include "/dev/stdin"
12.是否多余的逗号
main() { int arr[] = { 1, 2, 3, //here,ok? }; }
但是gcc编译顺利
13.逗号运算符
下面的输出会是什么?
main() { int a = (2+2,1+2); printf("%d\n", a); }
会是3
带逗号的表达式会返回最后一个的执行结果
14.printf打印float时怎么动态确定打印几位呢
#include <stdio.h> int main() { int a = 4; float b = 6.412355; printf("%.*f\n",a,b); return 0; }
输出是6.4124
其中*号起了作用
15.从文件初始化数组
新建一个文件arr.txt:
{1,2,3}, {4,5,6}
然后我们写我们的C文件1.c:
#include <stdio.h> main() { int arr[][3] = { #include "arr.txt" }; }
现在我们编译:
gcc 1.c -g
现在用gdb debug a.out。会发现arr是{{1,2,3},{4,5,6}}
当然你也可以直接在1.c中打印数组
其实你还可以发现,如下的初始化是合法的!(因为gcc的扩展):
#include <stdio.h> main() { int arr[100] = {[1 ... 90 ] = 1, [91 ... 99] = 2}; }
具体的初始化技巧见 C语言数组初始化技巧
16 结构体初始化
struct mystruct a = {0};
这会把每个成员置0
17 warning宏
#include <stdio.h> int main(int argc, const char *argv[]) { #warning:This is some warning message return 0; }
编译运行之,你会发现报了一个warning
18.使用LINE 和FILE来debug
__LINE__
和 __FILE__
19.函数指针
你会发现,函数指针是很有用处的。具体见:C语言函数指针的介绍和用途
函数指针可以让我们实现函数工厂,以及写出面向对象的代码。