C语言指针和数组
指针和数组结合
1、回顾
前面已经说过了数组,但是在这个地方结合指针再次探索一下数组
数组是相同数据类型变量的集合,在数组声明的时候已经确定了数组的长度,如果使用了不属于当前范围的,那么就会访问到其他地址的数据
# include <stdio.h>
int main(void){
int a[3] = {1,2};
int i = 0;
for(i = 0 ; i< 3;i++){
printf("对应的值是:%d\n",a[i]);
}
// 下面这就是错误的使用方式。因为a[4]这个不属于数组的范畴。访问到了其他地方的数据,非法访问
printf("a[3]对应的值是:%d\n",a[4]);
return 0;
}
而且之前没有说过的是数组名字是一个常量,所以无法进行下面这样的赋值:
# include <stdio.h>
int main(void){
int a[3] = {1,2};
int b[3] = {};
// 这里就相当于是两个常量进行赋值。如:2=3,显然是不可行的
b = a;
return 0;
}
这里也就解释了为什么之前不能够这样子来进行赋值,而是采用for循环,一次遍历里面的元素来进行赋值了。
再验证一下之前说的,数组名就是数组第一个元素的地址:
# include <stdio.h>
int main(void){
int a[3] = {1,2};
printf("数组第一个元素的地址是:%d\n",&a[0]);
printf("数组第一个元素的地址是:%d\n",a);
return 0;
}
控制台输出:
数组第一个元素的地址是:6487568
数组第一个元素的地址是:6487568
--------------------------------
Process exited after 0.08574 seconds with return value 0
请按任意键继续. . .
2、数组和指针的关系
上面已经介绍了,数组名是第一个元素的地址且是一个常量。指针刚刚好就是用来指向一个地址的变量,那么通过指针就可以建立起来和数组的关系。
先来个demo测试一下:
# include <stdio.h>
int main(void){
int a[3] = {1,2};
int * p;
p = a;
printf("数组的地址是:%d\n",a);
printf("数组的地址是:%d\n",p);
return 0;
}
控制台输出:
数组的地址是:6487552
数组的地址是:6487552
--------------------------------
Process exited after 0.0477 seconds with return value 0
请按任意键继续. . .
可以看到a和p指向的是同一块内存空间的地址,同时这里也说明了,数组名也是一个指针变量,指向了数组中的第一元素的地址。
那么接着再看:
# include <stdio.h>
int main(void){
int a[3] = {1,2};
int * p;
p = a;
printf("数组的地址是:%d\n",a);
printf("数组的地址是:%d\n",p);
printf("数组的第一个元素是:%d\n",*(p));
printf("数组的第一个元素是:%d\n",*(p+1));
return 0;
}
控制台输出:
数组的地址是:6487552
数组的地址是:6487552
数组的第一个元素是:1
数组的第一个元素是:2
--------------------------------
Process exited after 0.0751 seconds with return value 0
请按任意键继续. . .
p和a既然指向了同一块地址,而且是相同的数据类型的,那么a[i]就等价于是p[i],那么来验证下:
# include <stdio.h>
int main(void){
int a[3] = {1,2};
int * p;
p = a;
printf("数组的地址是:%d\n",a);
printf("数组的地址是:%d\n",p);
printf("数组的第一个元素是:%d\n",*(p));
printf("数组的第一个元素是:%d\n",*(p+1));
// 发现这里是可以来进行操作的
printf("数组的第一个元素是:%d\n",p[0]);
return 0;
}
控制台输出:
数组的地址是:6487552
数组的地址是:6487552
数组的第一个元素是:1
数组的第一个元素是:2
数组的第一个元素是:1
--------------------------------
Process exited after 0.07295 seconds with return value 0
请按任意键继续. . .
从这里可以再总结出来一个:p[i]等价于是*(p+i)。利用程序来验证一下:
# include <stdio.h>
int main(void){
int a[3] = {1,2};
int * p;
p = a;
printf("数组的地址是:%d\n",a);
printf("数组的地址是:%d\n",p);
printf("数组的第一个元素是:%d\n",*(p));
printf("数组的第一个元素是:%d\n",*(p+1));
printf("数组的第一个元素是:%d\n",p[0]);
printf("---------------------------------\n");
// 遍历数组
int j ;
for(j=0;j<3;j++){
printf("数组的元素是:%d ",*(p+j));
printf("数组的元素是:%d\n",p[j]);
}
return 0;
}
查看控制台输出:
数组的地址是:6487552
数组的地址是:6487552
数组的第一个元素是:1
数组的第一个元素是:2
数组的第一个元素是:1
---------------------------------
数组的元素是:1 数组的元素是:1
数组的元素是:2 数组的元素是:2
数组的元素是:0 数组的元素是:0
--------------------------------
Process exited after 0.08258 seconds with return value 0
请按任意键继续. . .
可以看到验证成功,数组和指针是有对应的关系的。
3、指针在数组中运算
指针只有在指向同一块连续空间中进行相减才有意义。如果在函数中需要使用到数组,那么需要来确定两个值,一个是数组名字,另外一个是数组长度;
看下运算:
# include <stdio.h>
int main(void){
int a[300] = {1,2};
int * p;
p = &a[50];
int * q ;
q = &a[60];
printf("数组中两个元素相差的个数是:%d\n",(q-p));
return 0;
}
看下控制台输出:
数组中两个元素相差的个数是:10
--------------------------------
Process exited after 0.1044 seconds with return value 0
请按任意键继续. . .
可以看到在数组中通过计算是可以获取得到对应的值的。
4、指针变量所占字节大小
C语言中提供了对应的计算方式来进行操作:sizeof(数据类型或者变量名)函数,返回值就是所占据的这种数据类型占据的字节数
首先通过程序来进行验证一下:
# include <stdio.h>
int main(void){
int a[10] = {1,2};
int * p ;
p = a;
// 查看指针变量所占用的字节大小
printf("p占用的字节大小是:%d\n",sizeof(p));
printf("int数据类型占用的字节大小是:%d\n",sizeof(int));
char ch = 'A';
char * c =ch;
printf("char数据类型占用的字节大小是:%d\n",sizeof(char));
printf("char指针类型占用的字节大小是:%d\n",sizeof(c));
return 0;
}
控制台输出:
p占用的字节大小是:8
int数据类型占用的字节大小是:4
char数据类型占用的字节大小是:1
char指针类型占用的字节大小是:8
--------------------------------
Process exited after 0.1491 seconds with return value 0
请按任意键继续. . .
通过上面的观察总结一下:
指针类型所占据的字节数都是8个字节,而每种变量类型都是其按照固定的格式来进行分配的。那么首先需要搞明白为什么指针类型的占据8个字节。
还是之前介绍过的地址总线的概念,因为我当前的操作系统是64位的,查看了下我的编译器是32位的。
地址总线应该是有64根的,那么就有2^64个状态可以表示:
0000000000000000000000000000000000000000000000000000000000000000
........................
1111111111111111111111111111111111111111111111111111111111111111
所能够占据的内存单元有这么多种取值范围,一共有2^64次种。根据数据类型来进行寻址,可以快速定位到对应的比特上去。
如果一个指针要是想来进行确定地址能够占据的位置,那么倒是是要保存位还是字节还是什么?首先需要排除的是位,计算机能够访问最小的单元是字节。
而上面的每一行代表的是一个内存单元地址,内存单元是从0开始的,那么最后一个就是2^62。但是内存单元是需要用来存储对应的01代码的,每个里面需要存储8位的01数据。64/8=8,那么也就说明了每个指针变量存储的是每种数据类型的内存单元地址的第一个,而指针之所以知道某种类型的变量的值占据了几个单元格是通过数据类型来决定的。