C语言事实上不简单:数组与指针

之前在写C的时候,没怎么留意数组。就这么定义一个。然后颠来倒去的使用即可了。只是后来碰到了点问题。解决后决定写这么一篇博客,数组离不开指针。索性就放一起好了。

如今我定义了一个数组:int cc[10];

环绕这个数组有好几种指针:cc, cc+1, &cc[0], &cc, &cc+1等等。你知道它们都是什么含义吗?试试执行下面带代码:

#include <stdio.h>

int main()
{
    int cc[10];

    printf("%x\n", cc);
    printf("%x\n", cc+1);
    printf("%x\n", &cc[0]);
    printf("%x\n", &cc);
    printf("%x\n", &cc+1);

    getchar();
    return 0;
}

cc,这是学数组时第一个接触的"指针",最为熟悉,它是数组的首个元素。

cc+1,这是指向数字第二个位置的指针。

&cc[0],这个事实上就是cc,指向数组的首个元素。

&cc。这是什么玩意儿?指向指针的指针?

&cc+1,假设上面的意思是指向指针的指针。那这个岂不是指向野地址了?

如果执行环境是32位机。而且数组首地址为0x28ff00。那么:

cc的结果为0x28ff00,这点毫无疑问。

cc+1的地址是0x28ff04而不是0x28ff01,由于一个int占用了4个字节的空间。cc+1事实上是当成cc+1*sizeof(int)来看待。

&cc[0]的结果是0x28ff00,cc[0]表示的是数组的首个元素。那么&cc[0]自然就是首个元素的地址了。&cc[0] == cc。

&cc,这个就难说了。指针cc的值是0x28ff00,&cc表示这个指针本身的地址,我们怎么可能会知道这个地址?输出是个随机地址吗?随机数的话这个输出全然没有意义啊。假设不是随机地址的话,难不成还是0x28ff00?这种话a不就等于&a了?明显不正确吧。

对于基本类型的指针,如int *tt; 那么*tt是其值,&tt是指针的地址,&tt != tt

可是上述的cc是个数组。实际上。&cc被编译成了&cc[0],可是其含义不同,&cc指向的是整个数组的开头。

&cc与cc的指向能够用下图来形象表示:

上图能够看出,&cc事实上代表的是int(*)[10],那么&cc+1就能够理解为cc + sizeof(cc)/4,之所以除以4是由于int型指针++事实上是移动了4个字节。

又或者说%cc == cc + sizeof(cc)/4 == cc + 10。所以&cc+1的值为0x28ff28。

可见我们寻常使用的数组名,并不能单纯的当成指针看待。数组名的本质是代表数组对象的变量名,是一个左值,是一个不能被改变的左值。

可是因为在程序中不保存数组的大小,所以通过数组名仅仅能訪问数组的左值。不能訪问数组的右值。

因为这个原因,数组名在作为右值使用的时候被赋予另外一个新的意义——指向数组第一个元素的指针。这就是array-to-pointer转换规则。

依据标准规定。仅仅有当数组名作为sizeof、&运算符的操作数的时候。它是一个左值,其类型为数组类型。除此之外的全部情况,数组名都是一个右值,被编译器自己主动转换为指针类型,这样的情况下我们就说数组名是一个指针。而且是一个指针常量。

接下来是另外一些有趣的东西,我们结合sizeof与数组输出各类值。

下面程序的输出结果是什么?建议思考后再执行程序来验证答案。

#include <stdio.h>

int main()
{
    int cc[10];
    printf("%d\n", sizeof(cc[0]));
    printf("%d\n", sizeof(cc));
    printf("%d\n", sizeof(&cc));
    printf("%d\n", sizeof(int(*)[10]));

    getchar();
    return 0;
}

sizeof(cc[0]),一个int的大小。输出4,没问题。

sizeof(cc),注意不要和上面搞混。这不是数组首地址的指针,cc在这里是左值。其为数组类型。所以结果为40。

sizeof(&cc),这个的答案应该是多少呢?注意了。cc在这里还是左值,其为数组类型,但&cc不同于cc,无论数组怎么复杂它始终是个指针,32位机上指针大小始终是4个字节。所以结果为4。

sizeof(int(*)[10]),这个事实上和上面的&cc是一个样的,代表了整个数组,但还是指针,所以结果相同为4。

练习:以下的程序输出结果是什么(如果32位机):

#include <stdio.h>

int main()
{
    int *p[2];
    printf("%d\n", *p);
    printf("%d\n", sizeof(p));
    printf("%d\n", sizeof(&p));

    getchar();
    return 0;
}

答案是:随机数、8、4

再来一个练习:下列程序的输出是什么?

#include <stdio.h>

int main()
{
    char str[]="hactrox";
    char *p = str;
    printf("%d %d\n", sizeof(str), sizeof(p));

    getchar();
    return 0;
}

答案:8、4(不要忘了‘\0‘)

时间: 2024-08-06 15:56:25

C语言事实上不简单:数组与指针的相关文章

C语言 二维数组与指针笔记

今天分析了C语言二维数组和指针的基本理解,感觉有点懵...代码记录一下,如果有大神临幸发现哪里有误,欢迎指正~~~ #include <stdio.h> #include <stdlib.h> #include <string.h> //void func(int p[][]) //这样写等同于void func(int **p) p++移动了四个字节,(*p)++移动了四个字节,不符合二维数组规律 //{ //} //列优先输出的函数(即竖着输出) void func

C语言学习_数组与指针2

数组其实是一种变相的指针,数组名同时也是指针,eg: CODE == &CODE[0]; 数组的加法: #include<stdio.h> #define SIZE 4 int main(void) { shortdates[SIZE]; short* pti; shortindex; doublebills[SIZE]; double* ptf; pti= dates;//把数组地址付给指针 ptf= bills; printf("%23s  %10s\n", &

C语言之不规则数组和指针

不规则数组是每一行的列数不一样的二维数组. 在了解不规则数组之前,先了解一下用复合字面量创建的二维数组.复合字面量是一种C构造,前面看起来像是类型转换操作,后面跟的是花括号括起来的初始化列表. (const int) {100} (int[3]) {1,2,3} 下面的声明把数组声明为整数指针的数组,然后用复合字面量语句块进行初始化,由此创建了数组arr. int (*(arr[])) = { (int[]) {0,1,2}, (int[]) {3,4,5}, (int[]) {6,7,8}};

C语言核心之数组和指针详解

寒假要开始猛刷<剑指offer>,先回顾一下C语言基础做个热身. 指针 相信大家对下面的代码不陌生: 1 int i=2; 2 int *p; 3 p=&i; 这是最简单的指针应用,也是最基本的用法.再来熟悉一下什么是指针:首先指针是一个变量,它保存的并不是平常的数据,而是变量的地址.如上代码,指针p中保存的是整型变量i的地址信息. 接下来看如何定义一个指针,既然指针也是一个变量,那么它的定义也和其它变量一样定义:如: int *p: .'*' 是间接寻址或间接引用运算符.上例中我们还

C语言学习004:数组与指针

在C语言中,字符串实际上就是字符数组,在内存中字符串"Shatner"存储的形式是这样的 由于C语言并不知道数组有多长,所以用"\0"表示字符串的结束位置,通过sizeof运算符可以取到字符串在内存中占用多少个字节 同样的字符串在下面的代码中获取的长度却不一样,你知道是什么原因么? #include <stdio.h> void SayHello(char msg[]){ printf("msg occupies: %i\n",siz

C语言 二维数组(指针)动态分配和释放(转)

C 二维数组(指针)动态分配和释放 先明确下概念: 所谓32位处理器就是一次只能处理32位,也就是4个字节的数据,而64位处理器一次就能处理64位,即8个字节的数据.如果我们将总长128位的指令分别按照16位.32位.64位为单位进行编辑的话:旧的16位处理器,比如Intel 80286 CPU需要8个指令,32位的处理器需要4个指令,而64位处理器则只要两个指令,显然,在工作频率相同的情况下,64位处理器的处理速度会比16位.32位的更快.而且除了运算能力之外,与32位处理器相比,64位处理器

15-黑马程序员------C 语言学习笔记---数组和指针

黑马程序员------<a href="http://www.itheima.com" target="blank">Java培训.Android培训.iOS培训..Net培训</a>.期待与您交流! ------- 四 数组和指针 01 数组名代表数组在内存中的首地址,表示的是地址信息,因此数组名可以理解为一个指针,不过数组名是一个常量,不能改变. #include <stdio.h> int main() { char nam

C语言之一维数组与指针

一维数组: 假如有一维数组如下: char a[3]; 该数组有3个元素,数据类型为char型,地址空间如下. 如果想访问数据,直接使用a[0].a[1].a[2]取出相应地址空间的值即可 一级指针: 指针即地址,char *b即定义一个指向char型数据的指针,int *b即定义一个指向int型数据的指针. int a=5; int *b=&a; 例子解析:定义一个int型数据a,值为5,定义一个指向int型的指针b,b的值为a的地址.使用*b就是b指向地址的值.地址空间如下. 二级指针: 二

C语言中的数组与指针

1. 数组的初始化 数组的初始化方法有很多,常用的方法有 定义时初始化 int arr[3]={1,2,3}; 或 int arr[3]={2}; //未初始化的元素全为0: 定义后遍历赋值初始化 int arr[3]; for(int i=0;i<3;i++) arr[i]=i; C99之后,出现了另一种十分方便的初始化方式.即利用元素位置来初始化该元素,使用方法如下 int arr[5]={[3]=1,3} 初始化后的结果 arr[5]={0,0,0,1,3} 此种方式的缺点是,后面的初始化