数组与指针

数组

数组是指具有相同类型的数据组成的序列,是有序集合。(教科书上的定义)
即:数组就是内存中一段连续的存储空间。那么我们怎么使用它呢?用数组名。也就是我们用数组名可以在内存中找到对应的数组空间,即数组名对应着地址。对应着首元素的地址,所以,我们可以通过数组的首元素地址来找到数组
数组名是一个地址(首元素地址),即是一个指针常量。

只有在两种场合下,数组名并不用指针常量来表示:
1. sizeof(数组名) ; sizeof返回整个数组的长度,而不是指向数组的指针长度。
2. &数组名 ; 产生的是一个指向整个数组的指针,而不是一个指向某个指针常量的指针。

&a[0] 与 &a 的区别:
两者的值相同,但意义不同。
&a[0]是指数组首元素的地址。&a是整个数组的地址。两者的值相同。

a+1 与 &a+1 的区别:

数组名a除了在上述两种情况下,均用&a[0]来代替。

a+1即等同于&a[0]+1。
注意:指针(地址)与常数相加减,不是简单地算术运算,而是以当前指针指向的对象的存储长度为单位来计算的。
即:指向的地址+常数*(指向的对象的存储长度)
&a[0]为数组首元素的地址。
故&a[0]+1 越过一个数组元素长度的位置。即:&a[0]+1*sizeof(a[0])。
&a为整个数组的地址。(只是用首元素地址来表示,其实际代表的意义是整个数组)
故&a+1 越过整个数组长度的位置,到达数组a后面第一个位置。 即:&a+1*sizeof(a)。

指针

  • 指针与取地址
#include<stdio.h> 
#include<stdlib.h> 
int main() 
{     
    int *a = (int*)malloc(sizeof(int));     
    *a = 1;     
    printf("\na = %d", *a);
    printf("\na heap address = %p", a);     
    printf("\n&a stack address = %p", &a);
    printf("\n");     
}

结果如下(程序打印出的结果不尽相同):

a = 1 
a heap address = 0x7fd67bc000e0 
&a stack address = 0x7fff528d8ac8

第一行表示 变量a的值为1
第二行表示 变量a所存储的内存地址0x7fd67bc000e0,(存放整数 ‘1’ 所用的4个bytes, 64位机器的话就是8个bytes),这块内存在堆上-heap
第三行表示 变量a本身(一个整数型指针 int* )的内存地址0x7fff528d8ac8,这块内存在栈上-stack。

#include<stdio.h>


int main()
{
    int num = 7;
    int *p = &num;//初始化指针,也可以写作int* p = &num;
    printf("%d 的地址是 %p\n", num, p);
    return 0;
}

//7 的地址是 0x7fff5a2d5b28

上面int p定义了一个指向int类型指针p(我们使用符号把p声明为指针),并初始化p使其指向int类型的变量num,这里&num中的&是取地址操作符,当&作用于一个对象上时,它返回了该对象的地址。
所以这里指针p指向了num所对应的地址。

  • 解引用与指针赋值
#include<stdio.h>


int main(void)
{
    int num = 7;
    int *p = &num;
    printf("数值%d所在的地址是 %p\n", num, p);
    printf("指针p所指向的地址为 %p , 该地址上所保存的值为%d\n", p, *p);
    *p = 100;
    printf("指针p所指向的地址为 %p , 该地址上所保存的值为%d\n", p, num);
    printf("num: %d\n", num);
    return 0;
}

数值7所在的地址是 0x7fff5ce40b28
指针p所指向的地址为 0x7fff5ce40b28 , 该地址上所保存的值为7
指针p所指向的地址为 0x7fff5ce40b28 , 该地址上所保存的值为100
num: 100

注意这里*操作符为解引用操作符,它返回指针p所指的对象(左值)。
我们可以对*p赋值(对左值赋值),从而改变p所指的地址上所保存的值,从而改变此地址所存储的变量num的值。

#include<stdio.h>

int main(void)
{
     int num = 7, another = -5;
     int *p = &num;
     p = &another;
     printf("%d\n", *p);//此时p指向了another,所以输出了another的值,即-5
     return 0;
}
//-5

当然,我们也可以给指针p赋值,使其指向另外一个地址,这样就改变了在解引用时获取的左值。

  • 指针表达式

注意:*与++优先级相同,且它们的结合性都是从右向左的。
例:对于 *cp++ ; 我们可以把它分解为: *cp 之后再 cp++
对于 *++cp ; 我们可以把它分解为:++cp 之后再*cp

数组与指针

#include<stdio.h>

int main(void)
{
     int val[100];
     for (int i = 0; i < 100; ++i)
          val[i] = i;
     int *p = val;///近似理解为 int *p = &val[0];
     ///这里发生了隐式指针转换:数组自动转换为指向第一个元素的指针
     printf("%d\n", *p); ///指针p指向val的第一个元素,即val[0]

     int t = 100;
     while (t--)
          ///可以直接对指针进行加减运算,就和迭代器一样
          printf("%d\n", *(p++));///输出0~99

     ///指针可以做差:
     int *p2 = &val[10], *p3 = &val[20];
     printf("%d\n", p3 - p2); //10
     printf("%d\n", p2 - p3); //-10

     ///还可以比比较大小:
     printf("%d\n", p2 < p3 ? p3 - p2 : p2 - p3); //10
     return 0;
}

注意:
两个指针直接相加是不允许的。(你要真想把两个地址值相加,把它们先都强制转换为int型即可)
两个指针直接相减在语法上是允许的。(但必须相对于同一个数组,结果是两指针指向位置相隔的元素个数)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值