数组、数据与内存单元 和 相关的字符串处理注意之处
s数组与内存单元
创建一个数组 a:array[0..n]of datatype,
创建数组,内存单元是连续开辟的
设数组的起始地址为address,而一个数据的长度为x个内存单元,则数组数据的存储地址为address,address+x,address+2x,…,address+kx,…,分别对应a[0],a[1],a[2],…,a[k],…的地址
程序可以通过名称来获得地址,如a为数组的起始位置;a[k]为数组的第(k+1)个数的地址,为a+x*k。
输入:程序读入一个数据到某一数组单元中:程序获得该数组单元的地址,然后把数据存放到该地址中
输出:程序输出某一数组单元的数据:程序获得该数组单元的地址,然后从该地址中获得数据
1.二维数组(数据类型以字符为类,一个字符占一个存储单元;以c为例,0..n代表有n-1个数,下表为0~n-1,0..m代表有m-1个数,下表为0~m-1)
s:array[0..m][0..n]of datatype
同样的,内存单元是连续开辟的,
如s:array[0..m][0..n]of datatype,二维数组初始地址为s[0][0],接着是s[0][1],s[0][2],s[1][0],s[1][1],s[1][2],s[2][0],s[2][1],s[2][2]。
而s[0..m-1][0..n-1]数组中,一个数据的长度为x个内存单元,s[p][q]的地址为s[0][0]+(n*p+q)*x。(以c为例,0..n代表有n-1个数,下表为0~n-1,0..m代表有m-1个数,下表为0~m-1)
A:字符串输入:程序会从给定的起始位置开始依次读入字符到内存单元中,在最后添加一个'\0'作为一个结束标志
输入a,此时s[0]的值为"a\000x"
输入abcd,此时s[0]的值为"abc",s[1]的值为"d\000\000"
输入abcdefghijklm,此时s[0]="abc",s[1]="def",s[2]="ghi",接下来的存储单元存储的是'jklm\000'
B:字符串输出
程序会从给定的起始位置开始依次从内存单元中取出内容并输出,直到遇到'\0'结束
注意:
1.开辟字符数组的大小问题:
如开辟个大小为n的数组和输入的字符串长度小于n时,程序会在最后加上'\0',即内存空间的内容是 s的内存地址:'x','x',…,'x','\0'。
而当输入的字符串长度大于等于n时,虽然程序只开辟了大小为n的数组,但这不妨碍程序继续存储内容到内存单元中(每存储一个数据,地址加1(一个字符的大小为1个内存单元)),而这有可能造成数据的覆盖问题,即程序给某个数据开辟了一个内存但是却被其它的数据使用了,造成数据的错误和混乱;也有可能导致后续字符串处理的错误,毕竟有可能'\0'被处理掉,或者一个新的'\0'出现(如2-3的程序)。当然,最后'\0'还是会加的,这就是右边的程序正常输出的原因。
2.strcpy与strncpy的区别
A:strcpy(s,__);
strcpy是复制字符串,左边的代码使用的是手打字符串,程序在字符串最后会自动加上'\0';右边的代码使用的是字符数组(字符串),如无意外最后也有'\0',所以字符串s最后不用加上‘\0'
当然如果被复制的字符串没有'\0'时,字符串s最后要加上‘\0',如1中输入的字符串长度大于等于n时引起的错误,如下面的程序。(分析见最下面)
B:strncpy(s,__+x,y)
而strncpy是复制字符串的一部分,很有可能字符串的一部分没有结束标志'\0',所以需要根据被复制的字符串的长度来加上’\0',如复制的长度为y,则s[y]='\0'(c中是以s[0]开始的)。
3.数据所在地址
程序结果说明:
1.数组开辟的空间是连续的,且满足——s[0..m-1][0..n-1]数组中,一个数据的长度为x个内存单元,s[p][q]的地址为s[0][0]+(n*p+q)*x。
2.主程序里数据的存储地址区间和子函数数据的存储地址区间是不一样的。
3.指针变量的存储地址区间和其它类型变量的存储地址区间不一样。
4.main子函数里数据的内存单元是按照创建变量的先后顺序 地址依次往下减少创建的。
5.子函数结束后,变量所分配的地址被撤销,这些地址供其它子函数变量使用。
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <malloc.h> 5 6 struct node 7 { 8 long x; 9 char c; 10 long y; 11 }info,*p; 12 13 long z; 14 char y; 15 long x; 16 double w[2]; 17 18 void test1() 19 { 20 long a; 21 char b; 22 long c; 23 double d[2]; 24 25 printf("\n----------\n"); 26 27 printf("F1:a-\t%ld\n",&a); 28 printf("F1:b-\t%ld\n",&b); 29 printf("F1:c-\t%ld\n",&c); 30 printf("F1:d[0]-%ld\n",&d[0]); 31 printf("F1:d[1]-%ld\n",&d[1]); 32 } 33 34 void test2() 35 { 36 long a; 37 char b; 38 long c; 39 double d[2]; 40 41 printf("\n----------\n"); 42 43 printf("F2:a-\t%ld\n",&a); 44 printf("F2:b-\t%ld\n",&b); 45 printf("F2:c-\t%ld\n",&c); 46 printf("F2:d[0]-%ld\n",&d[0]); 47 printf("F2:d[1]-%ld\n",&d[1]); 48 } 49 50 51 int main() 52 { 53 long a,b; 54 double c[2]; 55 long d; 56 char e[2][2]; 57 struct node f; 58 59 printf("z-\t%ld\n",&z); 60 printf("y-\t%ld\n",&y); 61 printf("x-\t%ld\n",&x); 62 printf("w[0]-\t%ld\n",&w); 63 printf("w[1]-\t%ld\n",&w[1]); 64 65 printf("\n----------\n"); 66 67 printf("a-\t%ld\n",&a); 68 printf("b-\t%ld\n",&b); 69 printf("c[0]-\t%ld\n",&c); 70 printf("c[1]-\t%ld\n",&c[1]); 71 printf("d-\t%ld\n",&d); 72 printf("e[0][0]-%ld\n",&e[0][0]); 73 printf("e[0][1]-%ld\n",&e[0][1]); 74 printf("e[1][0]-%ld\n",&e[1][0]); 75 printf("e[1][1]-%ld\n",&e[1][1]); 76 printf("f-\t%ld\n",&f); 77 78 printf("\n----------\n"); 79 80 p=(struct node *) malloc (sizeof(struct node)); 81 printf("p1-\t%ld\n",p); 82 p=(struct node *) malloc (sizeof(struct node)); 83 printf("p2-\t%ld\n",p); 84 p=(struct node *) malloc (sizeof(struct node)); 85 printf("p3-\t%ld\n",p); 86 p=(struct node *) malloc (sizeof(struct node)); 87 printf("p3-\t%ld\n",p); 88 89 printf("\n----------\n"); 90 91 printf("info-\t%ld\n",&info); 92 printf("info.x\t%ld\n",&info.x); 93 printf("info.c\t%ld\n",&info.c); 94 printf("info.y\t%ld\n",&info.y); 95 96 test1(); 97 test2(); 98 return 0; 99 }