1. 指针与数组
c语言中的数组要注意以下两点:
下面的方法存在问题,因为数组的大小必须在编译期作为一个常数确定下来。
a[3][4] 本质也是一个一维数组(包含3个元素),只不过一维数组中的元素是也是数组(包含4个元素)。
int ar[10] = { 0 }; 注意:数组名代表的是整个数组空间。由sizeof(ar)=40 可以体现。
三者的内容相同,但解释是不同的。
&a[0] 针对首个元素取地址。
ar 数组名包含的内容,恰好是数组首元素的地址。但是数组名和数组首元素的地址不能划为等号。
&ar 数组空间的地址
&ar[0] 和ar都是普通的整型指针
这里要明白,&ar实际类型是数组指针
二维数组 (实际没有二维数组,只是一维数组的元素还为数组)
对于二维数组而言,数组名同样表示数组首元素的地址,而ar的首元素还是个
数组,因此,对应的指针也应该是数组指针。
二维数组, int ar[3][4];
ar实质上是一个指针的指针, 即二级指针。
一个指针加一个数, 当然还是指针(即a+1是指针)
取值一个二级指针, 是一级指针(即指针), 所以还是指针, 不过类型发生了变化.
a+1的类型为int * [4].
而*(a+1)的类型则为int *, 也就是平常的指针。
因此,为二维 数组中某一元素赋值用*(*(ar+1)+1)= 100.
2. 非数组的指针
r为指针 即地址。
想往r中拷贝 就需要为r开辟空间。
malloc开辟的空间是10,后面的\0没有空间存储。此时不会报错的
原因是恰好第11个位置没有被占用,如果被占用了就会报错。
为了避免上述问题,开辟的空间加1.
char *r = (char *)malloc(strlen(s)+strlen(t)+1)
同理,要想往 char *name中拷贝就需要为name开辟空间
3. 作为参数的数组声明
(1)
a和b中的值均为数组首元素的地址
int a[5] = {1,2,3,4,5};
printf("%p",a); //打印出的是a的地址
由于整型数组没有结束标记,打印时 只能把a当做地址来打印。
char b[ ] = "hello";
printf(b); //打印出的是字符串 hello
原因:字符数组和字符指针可通过首地址输出整个数组,整形数组却不可以。原因分析如下:
String是一个类,会重载toString()函数,toString()返回其本身。所以直接输出String类的对象会输出具体字符串。而字符型数组在内存中的储存方式同String类一样,因此输出数组名并非输出数组首地址,而是直接输出数组内容直到/0;而整形数组只是整形的集合,所以其数组名仅仅是其首地址,需用for循环输出整个整形数组。
举例:
值分别为40和4
说明数组名和数组首元素地址并不能划为等号,只是数组名的值是首元素地址。
因此不能对数组进行整体赋值。即br = ar不可取。
两个fun函数等价。
在调用函数fun(br)时,表面上看起来像传输的是整个br数组,实际传输的是br的首地址
因此注意,如果函数的参数是以数组的形式传递,那么,数组形式要退化为指针。
4. 避免举偶法陷阱
混淆指针与指针所指向的数据。
*p空间存储的并不是hello字符串
系统会开辟两个空间,一是为hello开辟的静态常量空间 其实位置是0x0042201c
二是为指针变量*p在栈区开辟的空间0x0013ff7c。而空间0x0013ff7c存储的是hello空间的首地址0x0042201c。
陷阱一:以下两种操作,字符串的存储方式不同。
char *p = “hello”;
p[0] =‘H’; 程序会崩溃,原因是不允许修改 静态常量空间中的 字符串常量。
而char p[ ] = "hello";
p[0] = 'H'; 则没问题,p[]是数组空间,会在栈区开辟空间,在栈区修改数组的内容是完全可以的。
陷阱二:
char *p = "hello";
char *q = p;
此时,p和q对应的栈区空间地址不同,但是这两个地址中存放的内容是相同的,都是hello的存储空间的首地址,即两个指针指向同一个地址。
陷阱三:
此时,不能重复释放空间。
5. 空指针并非空字符串
char *p = NULL; //p没有任何指向
char *q =""; //q指向的内容为\0
6. 边界计算与不对称边界
数组 左闭右开 栈的生长方向是从高地址到低地址。
图中,内存上边是低地址 下面是高地址,所以i在高地址 a在低地址
如上程序会一直循环,
原因是:在内存中,a[10]的位置恰好为i,a[10]相当于对i赋值,这会导致i的值一直小于10。
栈:它的生长方式是向下的,是向着内存地址减小的方向增长。栈的开口是向下的,上面的底部是栈底,下面的开口是栈顶。
缓冲区设计
7. 求值顺序陷阱
短路求值
8. 运算符&& || ! 按位 & | ~(取反)
逻辑运算的结果只能是真或假