数组与指针(一)

指针与数组的思维导图笔记


用了两天时间认真的学习了一下c语言指针与数组的恩怨纠葛,真的是让我心力交瘁!下面直接上干货!

一、指针和一维数组

1、指针指向一维数组:

    int a[10], *pa;
    pa = a;  //指针指向数组头,相当于a[0];
    pa = &a[3];  //指针指向数组的第3个元素

2、指针做++和- -运算

和数组名a不同,pa的值可以被修改,因此可以做++和- -运算(跳过4个字节),指向下一个元素或前一个元素。配合指针运算符*,可以写出非常简练的表达式或语句。比如两个字符串(分别存储在字符数组str1和str2中)的拷贝,可以简化成如下的形式:

    char *pstr1 = str1;
    char *pstr2 = str2;
    while(*pstr1++ = *pstr2++) ;

另外一种写法:

    void MyStrcpy(char *detStr, char *srcStr)
{
        while((*detStr++ = *srcStr++) != ‘\0’)
    {
    }
}

3、指针做关系运算

因为数组元素是连续存放的,所以指向一维数组的指针变量也可以做关系运算。关系运算主要用在循环语句的条件中,比如:

    for( pa = a; pa<a+5; pa++ ) 
        printf(“%d”, *pa);

还可以写作:

    int i;
    for(i=0;i<n;i++,p++)
    {
        printf("%d", *p);
    }

二、指针和二维数组

重点是理解行指针和列指针的概念:对于二维数组a,数组名a是行指针,a+i则跳过i行,为了访问行上的元素,需要把行指针转换为列指针,方法是加*,即 *(a+i),这个地址在数值上等于a+i,但它是列指针,它加j后在列上跳过j个元素,即* (a+i)+j指向第i行第j列的元素,也就是说*(a+i)+j == &a[i][j];那么为了访问元素a[i][j](也就是取值),还需要再做一次指针运算,即,*(*(a+i)+j),它等价于a[i][j]。因为从一维数组我们知道,*(a+i)等价于a[i],所以 *(*(a+i)+j)也可以写作*(a[i]+j)。二维数组的每一行本来就可以看作是一个一维数组,数组名是a[i],所以*(a[i]+j)就是a[i]这个一维数组中的第j个元素。
数值上,它们是相等的: a == a[0] == &a[0][0] == *a。
我来简单的总结一下上面的内容:

*(a + i)+j == &a[i][j]——这是址;
*(*(a+i)+j) == a[i]+j——这是值;

还有一个需要掌握的是行指针变量 int (*p)[4],

它的优势是可以将二维数组的一行传递给某个函数。

既然有行指针就有列指针,列指针指向的是数据类型为二维数组的元素类型,因此他与同类型简单变量的指针的定义方法是一样的:int *p;

好吧,简单来说,一摞扑克牌一共是13*4=52张,就相当于我们将这摞牌分成了13行4列。
第一种摆放扑克的方法:要查找扑克牌中的一张牌的话,我们要做的就是一张一张的去找这张牌,其实就好比将这副牌看成了一位数组,那么就可以使用二维数组的列指针来寻址这些数组元素;所以列指针的定义方法和简单的变量的指针的定义方法是一样的。

从数组的第零行第零列寻址到第i行第j列则需要跳过i*n+j(其中n为一行元素的个数)因此p+i*n+j代表数组的第i行第j列,即&(p+i*n+j),*(p+i*n+j) === p[i*n+j] === a[i][j];这里的p是指向数组的指针;

第二种摆放扑克的方法就是将一副牌分成13摞,先查找这张牌在那一摞,然后在这一摞中一张一张的查找,相当于使用二维数组的行指针来寻址数组元素;

例:二维数组存储学生的成绩,每行存储一个学生,求指定学号的学生的平均成绩。

# include"stdio.h"
float ave(int(*pi)[3],int n)    //定义行指针变量pi,准备接收行指针
{
    int j;
    float sum=0,aver;
    for(j=0;j<n;j++)
    {
        sum+= *(*pi+j);   // 在该例中*(*pi+j)等于 *(*(score+2)+j)或者 *(score[2]+j)
    }
    aver= sum/n;
    return aver;
} 
int main()
{
    int score [3][3]={{1,2,3},{4,5,6},{7,8,9}};
    printf("ave= %.2f\n",ave(score+2,3));  //传递行指针score+2给pi
    return 0;
}

指针数组

每个元素都是一个指针值的数组。注意区别指针数组和上面定义的行指针变量(有点像函数指针和返回指针值的函数):

int * p[4];   int (*p)[4]; (前者是指针数组,后者是行指针变量)
int *fun( )   int (*p)( )  (前者是返回指针值的函数,后者是函数指针)
指针数组的每一个元素存储一个地址值,每个元素都可以当作同类型的指针变量一样去使用。使用前必须初始化。
int * p[4]; int a[4];
for(i=0;i<4; i++)
    p[i] =&a[i];

指针数组主要用于字符串的处理。下面的例子中用字符指针数组指向若干个字符串,在对字符串进行排序的时候,不需要挪动字符串本身,而只需要挪动指针数组元素即可,也就是说改变指向关系即可。这提高了程序的效率。

#include "stdio.h"
#include "string.h"
#define N 150
#define MAX_LEN 10

void sortString(char *p[], int n);

int main()
{
    int i, n;
    char name[N][MAX_LEN];    //定义二维数组;
    char *pstr[N];          //定义指针数组;
    printf("How many countries?");
    scanf("%d", &n);
    getchar();          //读走缓冲区的回车符;
    printf("Input their name:\n");
    for(i=0;i<n;i++)
    {
        pstr[i] = name[i];  //指针数组的第i行指向二维数组的第i行;
        gets(pstr[i]);      //输入第i个字符串到指针数组的内存;
    }
    sortString(pstr, n);
    printf("Sorted result:\n");
    for(i=0;i<n;i++)
    {
        puts(pstr[i]);
    }
    return 0;
}
/*用指针数组做函数参数,用索引排序代替物理排序;*/
void sortString(char *p[], int n)
{
    int i, j;
    char *temp = NULL;  //因为交换的是字符串的地址值,故temp定义为指针变量,为防止指针变量的地址出问题,所以将其定义为NULL;
    for(i=0;i<n-1;i++)
    {
        for(j=i+1;j<n;j++)
        {
            if(strcmp(p[j], p[i]) < 0)  //采用字符串函数strcmp来比较两个字符串的字典顺序;
            {
                temp  = p[i];
                p[i] = p[j];
                p[j] = temp;
            }
        }
     } 
 } 

指针数组的另一个用途就是带参数的main函数:int main(int argc, char * argv[ ]),用命令行方式运行程序时,可以给main函数传递参数,参数和程序名都是字符串,字符串的个数保存在变量argc中,字符串的首地址保存在argv指针数组中。

例:从命令行输入两个整数,计算并输出它们的和:

#include “stdio.h”
#include “stdlib.h”
int main(int argc, char*argv[])
{
    int a, b;
    a= atoi(argv[1]);
    b= atoi(argv[2]);
    printf("a+b= %d\n",a+b);     
 }

命令行输入:add 45 67
运行结果:a+b = 112

注意:上面的输入中,字符串“add”的地址存入了argv[0],“45”的地址存入了argv[1],“67”的地址存入了argv[2]。


思维导图见指针与数组(二)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值