指针与数组,指针与函数,指针与字符串

一:指针与数组

首先我想解释清楚指针与数组名的关系,由下面的代码引入问题,不知道大家有没有好奇过为什么它们三个是一样的?

#include<stdio.h>
int main(int argc,char *argv[])
{
    int a[5] = {1,2,3,4,5};
    printf("%p %p %p\n",a,&a,&a[0]);
    return 0;
}

这里写图片描述

那我们在看下面代码:

#include<stdio.h>
int main(int argc,char *argv[])
{
    int a[5] = {1,2,3,4,5};
    printf("%p %p %p\n",a,&a,&a[0]);
    printf("%p %p %p\n",a+1,&a+1,&a[0]+1);
    return 0;
}

这里写图片描述
答案显而易见,就是a&a[0]是一样的,但是&a虽然和它们的值一样,意义却不相同,因为&a代表的是一种类型的首地址,因此我要说数组是一种类型,就像intlong一样,它代表的是一种类型,比如int a[5]的类型就是int [5],这种类型代表的是一个包含五个int元素的类型,它与int b[10]的类型不同,int b[10]的类型是int [10]代表包含十个int元素的类型。所以呢,&运算符取出来的是类型的首地址,这时候它不是指针,还有一种意外情况是sizeof运算符,它的作用是计算类型所占用的字节数,因此sizeof(a) = 20,除了这两个特殊情况,其他情况均转换成指针,即除了在&和sizeof的时候,其余情况的数组名均转换成指针

(1)指针与一维数组:我们可以用数组名来遍历数组。看下面代码:

#include<stdio.h>
void main(void)
{
    int *p = NULL;
    int i;
    int a[5] = {1,2,3,4,5};
    for(i = 0;i < 5;i++)
        printf("%d ",*(a+i));
        printf("\n");
    for(p = a;p<a+5;)
        printf("%d ",*p++);
        printf("\n");
}

我们可以用数组名来直接作为指针,也可以将数组名赋给我们提前准备好的指针p。并且由于数组的所有元素在逻辑上是按顺序存放的,所以p指向数组中的一个元素,而p+1就指向它的下一个元素。但是我们不能依次对a++来取得后续元素的值,因为a只表示a[0]元素的地址,这是已经确定了的。还要注意p++和++p的不同:

*p++:先取得目前p的值所指向空间的值,然后立马对p的值加1;
*++p:先对目前p的值加1,然后再取P所指向空间的值;

(2)二维数组与指针数组。

#include<stdio.h>
void main(void)
{
    int a[5] = {1,2,3,4,5};
    int *p[5];
    int i;
    int **pp = p;        //定义一个2级指针让他等于p

    for(i = 0;i < 5;i++)
    {
        p[i] = &a[i];
        printf("%d ",*p[i]);          //p = &p[0];p0 = &a[0]; 所以p = &&a[0] 
    }                                        

    printf("\n");
    for(i = 0;i < 5;i++)
        printf("%d ",**(pp+i));      //pp = p; **pp = **p = **&&a[0] = a[0] = 1

    printf("\n");

p先与[5]结合,构成拥有5个元素的数组,数组中每个成员都是int *类型的,即都指向一个int元素,也就是a中的对应元素,p作为数组名,就已经是指针的指针了,所以我们可以像注释中那样描述。
注意:区别int(*p)[5] 和int *p[5]的不同:

int(*P)[5]:它是一个指向“拥有五个int类型元素的数组”的指针,长度为1。
int *p[5]:它是一个指针数组,有5个元素,长度为5,每个元素都是指针,并且指向的是int 类型的元素。

二:指针与函数

(1)返回指针的函数:int *f(int,int);
由于()的优先级高于*,所以f会先与()结合构成函数,因此上面的声明说明了函数f的返回值是一个指向int元素的指针,我们在链表的相关操作中就经常这样用,在函数的结尾return回来链表的头指针以便后续操作。
(2)指向函数的指针:int (*f)(int,int);
现在*f的身份发生了变化,它成为了一个指向函数的指针,一个函数的函数名比较特殊,它指向一个函数,是一个指针。现在f指向的这个函数参数为两个int类型元素,函数返回值也为int元素。我们经常把这种指针用在作为函数的形参:

int func(int,int,int(*f)(int,int));

这条函数声明就说明了func函数中的第三个参数是“返回值为int,并且参数为2个int类型元素”的函数,我们需要在声明的时候将函数的描述值说出来,但是在func函数中不一定就需要第三个参数,即就是那个“返回值为int,并且参数为2个int类型元素”的返回值。这也是我们有时候在看一些函数声明的时候会不懂的原因。这个问题我在博客中也说过:简单理解函数声明
(3)返回指向函数指针的函数:int (*func(int))(int,int);
上面的声明这样理解,func为函数,它是一个只有一个参数,并且为int类型的函数,但是它的返回值是一个函数指针,为int(*)(int,int),这个函数指针指向这样一个函数:返回值为int 类型,参数为两个int类型。(这一点也可以看上面的博客)

三:指针与字符串

#include<stdio.h>
void main(void)
{                                             //保存字符串的方法
    char *p = "linux c process";              //方法一:用一个指向字符串的指针p
    char a[] = "linux c process";             //方法二:用字符串数组
    char b[20];
    int i;

    printf("%s\n",                             //p是一个指针,%s输出即可
    for(i = 0;a[i] != '\0';i++)
    {
        *(b+i) = *(a+i);                        //我们现在把a中的每个元素都保存到了字符数组b中,
        printf("%c",*(b+i));                    //输出元素
    }
    printf("\n");
}

也就是字符串数组名a可以作为指针直接使用。注意:p是指向字符串首地址的,我们可以改变p的位置但是不能对p执行p++操作,可以重新找一个变量,让p借助此变量向后移动,以达到我们遍历的目的。

for(j = 0;j < strlen(p);j++)
{
    printf("%c",*(p+j));
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杨博东的博客

请我喝瓶可乐鼓励下~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值