指针(三)

一、用数组名访问二维数组

1.用数组名访问二维数组
        定义二维数组:
        int  a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}}
       图形:
                 1     2     3     4
                 5     6     7     8
                 9    10   11   12
   
因为二维数组是特殊的一维数组,所以
特殊的一维数组形式为 :
int   a[3]={第一行a1,第二行a2,第三行3}
       因为要用数组名a来访问二维数组,这就相当于用数组名a来访问特殊的一维数组。所以我们先把它当做是一个一维数组来考虑。
下图为数组a在内存中存储情况:

        假设我们把这个二维数组看成是一维数组,那么根据普通的一维数组,我们知道,数组名代表一维数组的地址,所以:
         数组名a是这个特殊的一维数组的地址,也就说数组的第一行地址为a
         a+0  是  数组的第一行地址
         a+1  是  数组的第二行地址
         a+2  是  数组的第三行地址
由这个我们有可以得出一下结论:
        *(a+0)表示取a+0地址中的内容也就是数组第一行地址中的内容
        *(a+0)=第一行a1

        *(a+1)表示取a+1地址中的内容也就是数组第一行地址中的内容
        *(a+1)=第二行a2

        *(a+2)表示取a+0地址中的内容也就是数组第一行地址中的内容
        *(a+2)=第三行a2

因为我们这是一个二维数组,所以“第一行a1”、“第二行a2”“第三行a3”也分别代表一个一维数组。所以“第一行a1”也是数组(1,2,3,4)的地址。
        所以:
        *(第一行a1)表示是数组(1,2,3,4)的值 1
        所以:
        1=*(第一行a1)=*(*(a+0))
       同理:
        5=*(第二行a2)=*(*(a+1))
       9=*(第三行a3)=*(*(a+2))
从这个规律发现,用数组名可以访问到二维数组每行的首个元素的值。
因为“第一行a1”是一个地址,为了方便我们观察我们用p来代替“第一行a1”

由上图可以清楚的看到,如果我们想要访问元素2,那么该怎么办?
关于数组(1,2,3,4)的地址我们在上面已经知道是“第一行a2”也就是现在的p,所以:
*p  表示的是取地址为p中内容,所以*p=1;
*(p+1)  表示的是取地址为p+1中的内容,所以*(p+1)=2
*(p+2)  表示的是取地址为p+2中的内容,所以*(p+2)=3
*(p+3)  表示的是取地址为p+3中的内容,所以*(p+3)=4
经过这样的代替,应该很好理解我们改怎样访问元素 2,现在我们开始用倒推的方式来推导出如何用数组名来访问二维数组的每一个元素。
例:用二维数组名来访问 元素  2
因为:  *(p+1)=2
又因为 p=第一行a1
所以:*('第一行a1'+1)=2
而又因为:'第一行a1'=*(a+0)=*a
所以: *(*a+1)=2
所以这样就可以实现用二维数组名来访问二维数组中的每一个元素。但是我们用的时候不可能是用倒推法,所以我们要总结一下规律:

       总结:
           二维数组a的数组名是    a
所以:二维数组的第一行的地址也就是   a   
           二维数组的第二行的地址也就是 a+1 
           二维数组的第三行的地址也就是 a+2 

所以:二维数组第一行地址存储的内容为     *a        或是a[0]
           二维数组第一行地址存储的内容为  *(a+1)    或是a[1]
           二维数组第一行地址存储的内容为  *(a+2)    或是a[2]

而二维数组第一行地址存储内容 *a 也正好是  二维数组第一行的行地址
所以: *a+i  表示第一行第i列元素的地址
所以:*(*a+i)  表示第一行第i列的元素(值)
同理:
所以: a[0]+i  表示第一行第i列元素的地址
所以:*(a[0]+i)  表示第一行第i列的元素(值)

总结:
        访问二维数组中的每一个元素的公式为:
        *(*(a+i)+j) 表示:访问二维数组a的第i行第j列的元素

        *(a[i]+j) 表示:访问二维数组a的第i行第j列的元素
其中
a[i]表示:第i行的首地址
j    表示:第j列
例子如下:
我们先用一般方式遍历二维数组;

打印如下

用二维数组名来遍历二维数组


打印如下:


二、二维数组指针定义、初始化
1、二维数组指针的定义、初始化
      在上面的说明中我们已经知道,二维数组名是指向行的,它不能对如下说明的指针变量p直接赋值:
int  a[3][4]={{10,11,12,13},{20,21,22,23},{30,31,32,33}},*p;
其原因就是p与a的对象性质不同,或者说二者不是同一级指针。C语言可以通过定义数组指针的方法,使得一个指针变量与二维数组名具有相同的性质。
       二维数组指针变量说明的一般形式为:
                             数据类型  (*指针变量名)[二维数组列数];
       其中“类型说明符”为所指数组的数据类型
       “ * ”表示其后的变量是指针类型

       如果将二维数组赋给一指针,应这样赋值:
int   a[3][4];
int   (*p)[4];    //该语句是定义一个数组指针,指向含4个元素的一维数组
p=a;            //将该二维数组的首地址赋给p,也就是a[0]或&a[0][0]
p++;              //该语句执行过后,也就是p=p+1;p跨过行a[0][]指向了行a[1][]
总结:
         数组指针:
                         定义一个指针变量,让这个指针变量指向一维数组的元素
         二维数组指针:
                         行指针,用来指向二维数组的每一行,存放的是行的首地址
                         定义格式:数据类型   (*行指针变量名)[数组第二维的长度];

用二维数组指针来实现变量二维数组


打印如下

就像前面所说,随便定义一个指针变量p,它的等级和二维数组名的等级不在一个级别所以我们定义了二维数组指针q,这样这个指针q的等级就和二维数组等级是同级别,这样就可以把q和二维数组名a等效的用,所以在上面的程序中只要把a换成p就可以了。

总结:只要指针变量p(假设一个变量)和数组a的等级相同,那么p就可以取代a.但是a不能想p想怎么用就怎么用。
          比如:p++这是正确的
                     a++这是错误的


三、指针数组和二维数组指针的区别
1、指针数组和二维数组指针变量的区别
int *p[3]={&a,&b,&c}; //p是一个指针数组
int (*p)[3];  //二维数组指针
区别:
         这两者虽然都可用来表示二维数组,但是其表示方法和意义是不同的。
         二维数组指针变量是单个的变量,其一般形式中“(*指针变量名)”两边的括号是不可少的。而指针数组类型表示的是多个指针(一组有序指针)在一般形式中“ *指针数组名”两边不能有括号。
例如:
         int (*p)[3];
         表示一个指向二维数组的指针变量。该二维数组的列数为3或分解为一维数组的长度为3
   
         int *p[3];
        表示p是一个指针数组,有三个下标变量p[0],p[1],p[2]均为指针变量。


四、字符串指针


1、字符串指针
      在C语言中,可以用两种方法访问一个字符串
    
    1>字符数组
                      char str[]="I Love China";
                      printf("%s\n",str);
                     说明:和前面介绍的数组属性一样,str是数组名,它代表字符数组的首地址。
    
    2>字符串指针指向字符串
                char *变量名="字符串内容";//“字符串内容”是常量
                char  *str="abc";   //定义并且初始化字符串指针
                char   ch='b';        //定义并且初始化字符变量
                char   *p=&ch;      //定义并且初始化字符指针
        
        字符串指针变量的定义说明与指向字符变量的指针变量说明是相同的。只能按对指针变量的赋值不同来区别。对指向字符变量的指针变量应赋予该字符变量的地址。

注意!
      1、使用字符数组来保存的字符串是 保存栈里的, 保存栈里面东西是  可读可写,所以我们可以改变里面的字符当把一个字符串常量赋值一个字符数组的时候,那么它会把字符串常量中的没有字符都放到字符数组里面
      2、使用字符指针来保存字符串,它保存的是字符串常量地址,常量区是  只读的,所以我们不可能修改字符串的字符

总结:
        char *p   只是定义了一个指针变量p并没有给它初始化,那么这个p是一个野指针,它并没有指向某一块内存空间,所以不允许访问野指针,如果给p分配内存空间就可以被使用了
scanf("%s",p);

2、二维字符数组概念

    1>二维字符数组
     例如:
              char   st[3][6]={"china","japan","korea"}; 
              或者
              char   st[ ][ 6]={"china","japan","korea"};
            
              用二维数组来保存多个字符串:
                  >用二维的字符数组可以存储多个字符串
                  >第一维存的是每个字符串的首地址
                  >每个字符串的长度,不能超过第二维长度


    2>一维字符数组
                char  ch[10]={'a','b'};   或    char    ch1[ ]="abc";

3>char型指针数组和字符数组区别

           1>char 类型的指针数组
            定义了一个指针数组name,并对name作了初始化赋值。其每个元素都指向一个字符串。
           比如:  char  *name[3]={"adf","dfg","dfgh"};

           2>字符串指针变量与字符数组的区别
           用字符数组 和 字符串指针变量 都可实现字符串的存储和运算。但是两者是有区别的。在使用时应该注意一下几个问题:
a:字符串指针变量本身是一个变量,用于存放字符串的首地址。而字符串本身是存放在以该首地址为首的一块连续的内存空间中并以'\0'作为串的结束。字符数组是由于若干个数组元素组成的,它可用来存放整个字符串。

b:对字符串指针方式
char  *p="I Love You";
可以写成:
char *p;
p="I Love You";

而对数组方式:
char  st[]={"I Love You"};
不能写成:
char st[];
st={"I Love You"};

而只能对字符数组的各元素逐个赋值!!!

总结:
         当一个指针变量在未取得确定地址前使用时危险的,容易引起错误。这是个野指针
但是对指针变量直接赋值是可以的。因为C系统对峙着变量赋值是要给以确定的地址。

总结2:
          字符串指针:     char *s="abc";
                                    指向可以改变 ,s是一个指针变量
                                    s="helloworld";
       
          字符数组 :   
                                    char s1[]="abc";
                                    s1是数组名,是一个常量






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值