(编程基础)指针和数组

指针和数组的区别:

(1)数据:指针保存数据的地址;数组保存数据的值

(2)访问:指针间接访问,首先取得指针的内容,把它作为地址,根据地址提取数据;数组直接访问数据

(3)用途:指针通常用于动态的数据结构,数组通常用于存储数目固定且数据类型相同的元素

(4)空间:指针使用malloc和free申请和释放空间,数组隐式分配和删除

(5)数据名:指针通常指向匿名数据,数组自身即为数据名


另外:数组和指针都可以在他们定义中用字符串常量进行初始化,看起来一样,但是底层的机制不一样:

指针:定义指针的时候编译器并不为指针所指向的对象分配内存空间,它只是分配指针本身的空间(32位机上通常为4个字节),除非在定义指针的时候同时赋值给一个字符串常量进行初始化,由于字符串常量存放于文本段,所以不允许通过指针修改字符串常量。

数组:定义数组的时候会根据下标分配内存,如果没有写明下标,会根据初始化的字符串常量的长度分配内存,可以通过数组下标修改数组的值。

#include <stdio.h>

int main()
{
    char b[] = "abc";
    printf("b[0] = %d\n", b[0]);
    printf("++b[0] = %d\n", ++b[0]);
    char *a = "abc";
    printf("a[0] = %d\n", *a);
    printf("++a[0] = %d\n", ++(*a));
    return 0;
}

测试结果如下:

cheny.le@cheny-ThinkPad-T420:~$ ./a.out
b[0] = 97
++b[0] = 98
a[0] = 97
段错误 (核心已转储)

可以看到验证了不能通过指针修改字符串常量的值,但是可以通过数组去修改,具体原因如下:

#include <stdio.h>

int main()
{
    char b[] = "bbb";
    char *a = "def";
    printf("&a = %p\n", &a);
    printf("&b = %p\n", &b);

    printf("a = %p\n", a);
    printf("b = %p\n", b);
    return 0;
}

运行结果:

cheny.le@cheny-ThinkPad-T420:~$ ./a.out
&a = 0x7fff93153108
&b = 0x7fff93153110
a = 0x40068c
b = 0x7fff93153110

从10和11行可以看到,”bbb“和”def“存储的位置是有区别的,”bbb“存储在栈区,栈区的数据是可以修改的,”def“存储在静态数据区(也就是代码段),数据是只读的

从7和8行可以看到,变量a和变量b都是存储在栈区的,另外b和&b的值是相等的,可以说明数组的数组名是一个指向第一个元素的指针,所以数组名的值跟第一个元素的地址是相同的


指针和数组的关联:

在KRC里面有这么一句话:‘’指针和数组是相同的仅当他们作为函数定义的形式参数“。

(1)”表达式中的数组名“就是指针

(2)c语言把数组下标作为指针的偏移量

(3)”作为函数参数的数组名“等同于指针


这里需要顺带的解释下形参和实参的区别:

形参:是一个变量,在函数定义或函数声明的原型中定义,又称”形式参数“, 例如:swap(int *a, int * b);

实参:在实际调用一个参数时所传递给函数的值,又称”实际参数“,例如swap(i, j);


数组和指针可交换性总结:

(1)用a[i]这样的形式对数组访问总是被编译器”改写“或者解释为向*(a+i)这样的指针访问

(2)指针始终就是指针,他绝对不可能改写成数组,你可以用下标的形式访问数组,一般都是指针作为函数的参数时,而且你知道实际传递给函数的是一个数组

(3)在特定上下文中,也就是他作为函数的参数(也只有这种情况),一个数组的声明可以看作是一个指针,作为函数参数的数组(就是在一个函数的调用中)始终会被编译器修改成指向数组的第一个元素的指针

(4)当把一个数组定义成函数的参数的时候,可以选择把他定义成数组,也可以定义成指针,不管选择哪种方法,在函数内部实际上获得的都是一个指针。

(5)在其他所有情况下,定义和声明必须匹配,如果定义了一个数组,在其他文件中对他进行声明的时候也必须把他声明为数组,指针也是如此。


给出一下测试的例子:

#include <stdio.h>

void p(char *a)
{
    printf("&a = %p\n", a);
    printf("&a[0] = %p\n", &a[0]);
    printf("&a[1] = %p\n", &a[1]);
}

int main()
{
    char a[] = "abc";
    p(a);
    return 0;
}

测试结果如下:

cheny.le@cheny-ThinkPad-T420:~$ ./a.out
&a = 0x7fff42747fe0
&a[0] = 0x7fff42747fe0
&a[1] = 0x7fff42747fe1
这个可以看到形参a是一个指针,值是0x7fff42747fe0,而数组第一个元素的地址就是0x7fff42747fe0,这个说明了总结(3)


#include <stdio.h>

void p(char a[])
{
    printf("&a = %p\n", a);
    printf("&a[0] = %p\n", &a[0]);
    printf("&a[1] = %p\n", &a[1]);
}

int main()
{
    char a[] = "abc";
    p(a);
    return 0;
}

测试结果如下:

cheny.le@cheny-ThinkPad-T420:~$ ./a.out
&a = 0x7fff73a4dca0
&a[0] = 0x7fff73a4dca0
&a[1] = 0x7fff73a4dca1
这段代码跟前一段代码的差别仅仅就是形参由指针变成了数组,但是得到的结果是一样的,a的值还是实参数组的第一个元素的地址,这个说明了总结(4)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值