C语言学习笔记(18) 指针数组和数组指针分析

摘要:总结了指针数组和数组指针的定义,以及main函数的入口参数的意义,每一个部分给出一个例子加深理解。


一、三个问题

   1.一维数组名代表了数组首元素的地址,二维数组名呢?

    我的理解也是的,但是数组首元素的地址。

    2.假设数组名为a,那么a和&a的地址值相同,意义不同,那么指向它们的指针类型相同吗?

    答案是不同,这一点下面会解释到,因为a和&a的意义不同,虽然在编译的时候会通过,但是会出警告,数组指针的类型是带有元素个数信息的。

    3.数组的类型到底是什么?比如int a[10],那么这个数组的类型就是int 吗?

    答案是int[10]


二、定义数组类型

    c语言通过typedef为数组类型重命名

    typedef type(name)[size];

    数组类型:

    typedefint(AINT5)[5];

    typedeffloat(AFLOAT10)[10];

    数组定义:

    AINT5iarray;

    AFLOAT10farray;

    这样子定义的数组也是比较一目了然的,所以先来回答上面的第三个问题,数组其实是有自己特定的类型的,数组的类型由元素类型和数组大小共同决定的,比如int a[5],那么这个数组类型应该称之为int[5]。


三、数组指针

    数组指针用于指向一个数组。

    数组名是数组首元素的其实地址,但不是数组的起始地址。

    通过取地址符&于数组名获得数组的起始地址。

    可通过数组类型定义数组指针:ArrayType* pointer

    也可以直接定义;type(*pointer)[n]

       pointer为数组指针的变量名。

       type为指向的数组的类型。

       n为指向的数组的大小。

    这里有个例子,可以加深理解:

<span style="font-size:18px;">#include <stdio.c>
 
typedef int(AINT)[5];
typedef float(AFLOAT)[10];
typedef char(ACHAR)[9];
 
int main(void)
{
    AINT5 a1;//定义了一个数组,名为a1,大小为5,int[5]类型
    float fArray[10];//定义一个float类型的数组,大小为10,数组名称为fArray
    AFLOAT10 *pf=&fArray;//定义一个数组指针,并将上述定义的数组地址赋给这个指针,数组地址给数组指针
    ACHAR9 cArray;//定义一个名称为cArray的数组,大小为9
    char(*pc)[9]=&cArray;//定义了一个数组指针,并把数组的地址赋给它
    char(*pcw)[4]=cArray;//定义一个数组指针,并把数组首元素的地址赋给它
   
    inti = 0;
   
    printf("%d   %d \n",sizeof(AINT5),sizeof(a1));//这里的打印是为了说明AINT5是代表的数组类型和a1的大小是一样的
   
    for(i=0;i<10;i++)
    {
           (*pf)[i]=i;//给fArray里的数组元素赋值
       }
      
    for(i=0;i<10;i++)
    {
           printf("%f\n",fArray[i]);//将元素值打印出来
       }
   
    printf("%0x,%0x, %0x\n",&cArray,pc+1,pcw+1);//打印出cArray的地址,然后pc和pcw都加一,这里是为了表示数组指针再+1之后的值
   
    return0;
    }
    编译运行之后,结果如下:
    20   20 
    0.000000
    1.000000
    2.000000
    3.000000
    4.000000
    5.000000
    6.000000
    7.000000
    8.000000
    9.000000
    bfadd05b,bfadd064, bfadd05f</span>

    最后一行是需要注意的地方,后面两个地址在首地址的基础上均加上了各自定义时指定的大小,这里计算的公式为a+1=(unsigned int)a+sizeof(*a),a的绝对值加上里面元素的大小,由于pc和pcw均属于数组指针,所以其大小也是数组的大小,这里应该明白了吧,前面打印AINT5和a1做比较,也是为了这个结果做铺垫。


四、指针数组

    指针数组是一个普通的数组。

    指针数组中的每一个元素都是一个指针,如下图。

    数组指针的定义:type* pArrayn[n];

        type*为数组中每个元素的类型

       pArray为数组名

       n为数组的大小

   

    下面给出一个例程进行分析:

<span style="font-size:18px;">#include <stdio.h>
#include <string.h>
 
/*该函数三个参数,const char* key,是一个常量指针,后面的table也是,最后规定了一个固定大小的size*/
int lookup_keyword(const char* key,constchar* table[],const int size)
{
    intret = -1;//如果匹配都不成功,就返回-1
   
    inti = 0;
   
    for(i=0;i<size;i++)
       {
           if(strcmp(key,table[i])==0)//这里是将key和table表中的字符串进行比较,相等就返回i,并且跳出
              {
                  ret=i;
                  break;
                  }
       }
   
    return ret;//返回上面得到的i,或者-1
   
    }
 
#define DIM(a) (sizeof(a)/sizeof(*a))//求解数组的大小
 
int main()
{
    const char* keyword[]={//这是一个指针数组,数组里面存放的都是指针
                 "do",
           "for",
           "if",
           "register",
           "return",
           "switch",
           "while",
           "case",
           "static"
       };
    printf("%d\n",lookup_keyword("return",keyword,DIM(keyword)));//利用lookup_keyword对输入的参数进行比较并输出结果
    printf("%d\n",lookup_keyword("main",keyword,DIM(keyword)));
      
}</span>

    其中要紧的地方都已经备注了,这里就是利用指针数组来做比较匹配,最后输出的结果是4和-1,因为return我们匹配到了,main没有。


五、main函数的入口参数

    main函数可以理解为是操作系统调用的函数。

    在执行程序的时候可以向main函数传递参数。

    intmain()

    intmain(int argc)

    intmain(int argc,char* argv[])

    intmain(int argc,char* argv[],char* env[])

    其中,inr argc是命令行参数的个数,char* argv[]是存放命令行参数的数组,最后保存环境变量的数组,这个我想凡事移植过u-boot的人都会了解吧,我们的bootcmd是怎么传进去的,我们的env是如何设置的,就是因为main函数是有入口参数的。其实我们在linux下面用命令行操作也是这么个道理罢了。

    下面这个例子可以打印出我们输入到main函数的参数:

<span style="font-size:18px;">#include <stdio.h>
 
int main(int argc,char* argv[])
{
    inti =0;
    for(i=0;i<argc;i++)
    {
       printf("%s\n",argv[i]);
       }
   
    return0;
    }
编译运行后结果如下:
./1-3
my
name
is
linux</span>

    第一个参数是我们的程序名称,是argv[]当中的第一个参数,后面都是我输入的参数,都是从argv[]这个数组中打印出来的。

    下面可以加入env环境变量的,来打印,程序如下:

<span style="font-size:18px;">#include<stdio.h>
 
int main(int argc,char* argv[],char* env[])
{
    int i =0;
    for(i=0;i<argc;i++)
    {
       printf("%s\n",argv[i]);
      }
      
    printf("\n");
    printf("\n");
    printf("\n");
    printf("here start outputtingenv");
   
    for(i=0;env[i]!=0;i++)
    {
       printf("%s\n",env[i]);
       }
   
    return 0;
    }
编译运行,我们看到如下输出:
./1-3
 
 
here start outputtingenvORBIT_SOCKETDIR=/tmp/orbit-root
HOSTNAME=embedclub
IMSETTINGS_INTEGRATE_DESKTOP=yes
GPG_AGENT_INFO=/tmp/keyring-SW0jQe/gpg:0:1
TERM=xterm
SHELL=/bin/bash
XDG_SESSION_COOKIE=025040522db1b6f52543dd1f00000019-1444404242.269127-275396613
HISTSIZE=1000
WINDOWID=31457283
GNOME_KEYRING_CONTROL=/tmp/keyring-SW0jQe
QTDIR=/usr/lib/qt-3.3
QTINC=/usr/lib/qt-3.3/include
IMSETTINGS_MODULE=IBus
USER=root
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.tbz=01;31:*.tbz2=01;31:*.bz=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:
CCACHE_DIR=/var/cache/ccache
SSH_AUTH_SOCK=/tmp/keyring-SW0jQe/ssh
SESSION_MANAGER=local/unix:@/tmp/.ICE-unix/2418,unix/unix:/tmp/.ICE-unix/2418
USERNAME=root
DESKTOP_SESSION=gnome
MAIL=/var/spool/mail/root
PATH=/usr/lib/qt-3.3/bin:/usr/lib/ccache:/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin:/usr/local/arm/4.3.2/bin:/root/bin:/usr/local/arm/4.3.2/bin
PWD=/home/passionbird/project/object-c/xia_array_pointer_1
XMODIFIERS=@im=ibus
CCACHE_UMASK=002
GDM_KEYBOARD_LAYOUT=us
LANG=zh_CN.UTF-8
GNOME_KEYRING_PID=2408
GDM_LANG=zh_CN.UTF-8
GDMSESSION=gnome
SSH_ASKPASS=/usr/libexec/openssh/gnome-ssh-askpass
HISTCONTROL=ignoredups
HOME=/root
SHLVL=2
GNOME_DESKTOP_SESSION_ID=this-is-deprecated
LOGNAME=root
QTLIB=/usr/lib/qt-3.3/lib
CVS_RSH=ssh
DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-19MhovU57w,guid=deb6a7fcf019d580d5bcb9a1000000ff
LESSOPEN=|/usr/bin/lesspipe.sh %s
WINDOWPATH=1
DISPLAY=:0.0
G_BROKEN_FILENAMES=1
XAUTHORITY=/var/run/gdm/auth-for-root-ojRS5L/database
COLORTERM=gnome-terminal
_=./1-3
OLDPWD=/home/passionbird/project/object-c</span>

    这些都是什么?仔细看清楚就可以明白,这些都是我们Linux下的环境变量,这也是利用main函数的入口参数和指针数组打印出来的。因为argv[]是操作系统调用的,所以操作系统是可以将当前系统的环境变量给你传递进来。


六、小结

    数组指针本质上是一个指针。

    数组指针指向的值是数组的地址。

    指针数组本质上是一个数组。

    指针数组中每个元素的类型是指针。

    这篇帖子就总结到这里,如有不正确的地方还请指出,大家共同进步!

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值