照这么说的话,c and pointers 中的情况就不存在了,也就是说遵循ANSI C不会把strlength(X)-10>0这个表达式判断错。
C expert中前后矛盾
#define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0])
2. 关于BUG
switch后面的i可以是整形或者是整形的代数运算
注意const int i这个i并不是整形。。。如果用case i:就会出错。
如同c pinter中所说,标准中相邻的字符串可以自动合并,所以以前的定义是这样
“11111 /
222222 /
3333”
(实际证明这种情况下/一定要贴着字符才不会有空格出现在最后的字符串中)
而现在是
"11111”
”22222”
”3333“
字符串尾部的/0会被自动删除,然后合并。
SYRLAC &在R和L之间
side effect sequence point 这里指出了意群的概念,就是不同的sequence point之间是一个意群。
int a = *b/*c ---- 变成注释了。。。
如何让程序返回一个指向部分内存的指针:
与C pointer相斥的说明:
enum也和struct一样有标签
优先级判定:
#define和typedef的区别:
后者是一种彻底的封装,不能再往里面填东西。另外对于几个连续变量的生命,typedef能够保证为同一种类型。
在不同的名字空间重名是没有问题的。
呵呵。。。。
左值就是指值存储的位置,如果不能确定存储位置,就不能做左值。右值。C语言为数组引入了可修改的左值的概念,就是说数组名,数组名有确定的存储位置,所以是左值,但是数组名不能被修改,所以是不能被修改的左值。这个是数组和指针的重要不同之一。比如函数传参传入是按数组的方式传入的,那么在函数中就不能修改这个数组名,而如果以指针的形式传入,则可以修改。
BSS block started by symbol 呵呵,better save space
共享库的虚拟地址空间布局:
alloca()分配的内存位于堆栈中
在绝大部分操作系统中,堆栈是向低地址增长的。
函数调用中的栈分布:
悬垂指针
微软的几种内存模型:
small
large
medium
compact
__near
__far
__huge
说上面的是修饰左边的,而const和volatile是修饰右边的。不对吧,const是修饰近的吧。?//FIXME//确实如此,如果const和volatile右边紧跟long或者int,就表示他们是修饰long或者int的,否则就表示他们修饰左边的*。
标签存储的意思?
堆中的变量都是没有符号的。只能通过指针来访问。
brk指针的存在。。
alloca是建立在堆栈上的动态内存分配,所以没有内存泄露的问题。但是如果处理器不支持堆栈,那么alloca就没有很好的可移植性了。
总线错误:
重要!!!如何判断一个程序是不是由于堆栈空间用完退出。
% dbx a.out
(dbx) catch SIGSEGV
(dbx) run
…
signal SEGV (segmentation violation) in
at 0x…
(dbx) where
如果可以看到调用链,则说明堆栈未用完,如果看到
fetch at 0x.. failed – I/O error
(dbx)
则说明堆栈很有可能用完,上面的地址就是堆栈地址。
此时可以通过ulimit更改堆栈大小
进城地址总空间决定于交换空间大小
系统不支持在信号处理函数中使用库函数!!
使用longjmp可以让程序在捕捉到ctrl+c后重新执行。(SIGINT)
C语言中的类型提升:
printf(sizeof ‘A’) 输出是4,因为经过了类型提升。
函数原因出来后,向函数传参后,不会出现先提升之后再函数内部又被裁减的情况了。之前之所以会这样是为了编译器设计的方便。
sigset比起signal来,就不用每次都设置信号处理函数了。//FIXME
Cdecl的实现P198未看,使用FSM实现的。 //FIXME
数组和指针不能互换的几种情况:
C expert中对指针相比于数组而言的优化程度没有做准备说明,但是c pointer中说有很大优化?究竟优化在什么地方//FIXME
函数传参不能传结构体?为什么?函数为什么不能返回函数或者数组?后者好理解,前者呢?//FIXME
函数究竟是传址还是传参,这个有待商量,看是怎么理解//FIXME
关于初始化指针数组 //FIXME
书上说了三种方法:
1. int *weight[] = {
{1, 2, 3, 4, 5},
{6, 7}
}
这样在最新的gcc中是不会编译不过的,但是会报错,说是把整形转成了指针。
2. int *weight[] = {
“time”,
“time”
}
这样按照书上说是正确的初始化方法,但是仍然会报错,说指针类型并不完全兼容。
3. int *weight[] = {
row_1,
row_2
}
然后在另外的地方定义的int row_1[] = {1, 2, 3, 4, 5, –1};
呵呵,这样一点错都没有报了。
所以以后可以用第三种方法来初始化。
ANSI C中定义的数组和指针相等的时候:
1. 表达式的数组名(与声明不同)被编译器当做一个指向改数组第一个元素的指针;
2. 下表总是与指针的偏移量相同;
3. 在函数参数的声明中,数组名被编译器当做指向该数组第一个元素的指针。
通过了测试,在被传参的函数中调用sizeof(数组名),结果无论传的是指针还是数组,结果都是4。
其余的时候,比如extern char buf[X]和 extern char *buf就不同。因为这时候buf[X]表示的是一个数组元素,而buf+X则表示的是一个数组元素的地址。
PDF的237页,也就是书得221页下面使用malloc的方法是错误的,这样就没有方法free了。
关于数组和指针参数如何被编译器修改,也就是说编译器如何匹配传参和形参中间关于数组的部分:
从中间可以看出规律,所有**的数组在传参的时候都会被匹配成**的指针,而**的指针在传参的时候都不用变。另外关于char **argv的说法也可以想想。
C expert PDF P244页中所说的普通的多维数组是相对于确定长度的特殊数组而言的。C语言中是不能传递不知道长度的数组的。这是因为它的传值方式决定的。
举例如下:
另外
也就是说可以
my_function(int my_array[][20]);
或者
my_function(int (*my_array)[20]); //这是和上面的数组的数组转成数组的指针相符合的。
之后还提到了4种给函数传数组参数的方法:
1. 传 my_array[10][20]
2. 传 my_array[][20]
3. 将数组改为一个指向向量的指针数组,也就是所谓的Iliffe向量,必须要改,改后就不与上面说的那个**argv和(* argv)[x]的不一样的说法冲突了,这样就可以穿** argv的参数了。
4. 放弃多维数组的方式,使用自己的下面方式。也就是所谓的flatten memory方式?
用strings 查看信息:
这个我领教过,用strings查看编译器版本,查看平台版本,镜像组成各部分。。。
用malloc模拟动态数组的优缺点,和另外一种动态增长数据结构的方法---链表的优劣。
Sample Code:
my_function_1(int fruit[2][3][5])
{
;
}
my_function_2(int fruit[][3][5])
{
;
}
my_function_3(int (*fruit)[3][5])
{
;
}
int main(void)
{
int apricot[2][3][5];
my_function_1(apricot);
my_function_2(apricot);
my_function_3(apricot);
int (*p)[3][5] = apricot;
my_function_1(p);
my_function_2(p);
my_function_3(p);
int (*q)[2][3][5] = &apricot;
my_function_1(*q);
my_function_2(*q);
my_function_3(*q);
}