摘要:总结了指针数组和数组指针的定义,以及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[]是操作系统调用的,所以操作系统是可以将当前系统的环境变量给你传递进来。
六、小结
数组指针本质上是一个指针。
数组指针指向的值是数组的地址。
指针数组本质上是一个数组。
指针数组中每个元素的类型是指针。
这篇帖子就总结到这里,如有不正确的地方还请指出,大家共同进步!