c语言二维数组.docx
- 文档编号:3545224
- 上传时间:2022-11-23
- 格式:DOCX
- 页数:11
- 大小:21.16KB
c语言二维数组.docx
《c语言二维数组.docx》由会员分享,可在线阅读,更多相关《c语言二维数组.docx(11页珍藏版)》请在冰豆网上搜索。
c语言二维数组
关于二维数组传参做形参
分类:
LinuxC基础今天开始嵌入式2011-08-2619:
0610773人阅读评论(3)收藏举报
编译器stringfunctionsystem存储
二维数组的存储方式是和一维数组没什么区别,但是用二维数组做参数,它的形参该怎样写?
要注意的是:
函数中的形参其实就相当于一个声明,并不产生内存分配,形参的目的就是要让编译器知道函数参数的数据类型。
正确的是:
voidFunc(intarray[3][10]); voidFunc(intarray[][10]);可以省略第一维的大小
错误的是voidFunc(intarray[][].这样的用法只能在初始化时可以用);这样写也是错误:
voidFunc(constintm,constintn,intarray[m][n]);或voidFunc(intm,intn,intarray[m][n]);大家都知道数组的索引必须是个常量表达式,voidFunc(constintm,constintn,intarray[m][n]);如果constintm没有初始化,那么系统将m或n自动初始化为0,所以这样些是不对的
如果我们采用这样voidFunc(int**array,intm,intn)的形式,那么在实际的函数调用是,我们就要进行强制转换才可以用,我们可以这样调用voidFunc((int**)array,intm,intn);在函数调用时,要把数组形式写成指针形式如*((int*)array+n*i+j);直接写intarray[i][j]会导致错误,编译可以通过,在VC编译器中执行会出现异常,DEV编译器会出现一个随机值,原因就在于如果写成intarray[i][j],编译器无法正确的寻址,当然各种编译器对它的处理结果是不一样的。
如果我们的形参是数组,那么我们在函数体中可以用指针也可以用数组形式,但是如果我们形参数中用的是指针,最好也用指针,有时用数组形式会出错,二维数组就是这样
========================================================================================================
以下是网上摘抄的一段:
首先,我引用了谭浩强先生编著的《C程序设计》上面的一节原文,它简要介绍了如何将二维数组作为参数传递,原文如下(略有改变,请原谅):
[原文开始]
可以用二维数组名作为实参或者形参,在被调用函数中对形参数组定义时可以指定所有维数的大小,也可以省略第一维的大小说明,如:
voidFunc(intarray[3][10]);
voidFunc(intarray[][10]);
二者都是合法而且等价,但是不能把第二维或者更高维的大小省略,如下面的定义是不合法的:
voidFunc(intarray[][]);
因为从实参传递来的是数组的起始地址,在内存中按数组排列规则存放(按行存放),而并不区分行和列,如果在形参中不说明列数,则系统无法决定应为多少行多少列,不能只指定一维而不指定第二维,下面写法是错误的:
voidFunc(intarray[3][]);
实参数组维数可以大于形参数组,例如实参(zhihui3409注:
应该是形参)数组定义为:
voidFunc(intarray[3][10]);
而形参(zhihui3409注:
应该是实参)数组定义为:
intarray[5][10];
这时形参数组只取实参数组的一部分,其余部分不起作用。
[原文结束]
大家可以看到,将二维数组当作参数的时候,必须指明所有维数大小或者省略第一维的,但是不能省略第二维或者更高维的大小,这是由编译器原理限制的。
根据编译原理可知,如果我们省略了第二维或者更高维的大小,编译器将不知道如何正确的寻址。
但是我们在编写程序的时候却需要用到各个维数都不固定的二维数组作为参数,这就难办了,编译器不能识别啊,怎么办呢?
不要着急,编译器虽然不能识别,但是我们完全可以不把它当作一个二维数组,而是把它当作一个普通的指针,再另外加上两个参数指明各个维数,然后我们为二维数组手工寻址,这样就达到了将二维数组作为函数的参数传递的目的,根据这个思想,我们可以把维数固定的参数变为维数随机的参数,例如:
voidFunc(intarray[3][10]);
voidFunc(intarray[][10]);
变为:
voidFunc(int**array,intRowSize,intLineSize);
在转变后的函数中,array[i][j]这样的式子是不对的(不信,大家可以试一下),因为编译器不能正确的为它寻址,所以我们需要模仿编译器的行为把array[i][j]手工转变为:
*((int*)array+LineSize*i+j);即把二维数组当作一维数组来处理,这是比较容易理解的方式。
其它方式见下面总结的第二点。
数组作为形参的问题总结:
1一维数组作为函数形参
数组作为形参时,编译器通常只会检查数组形参关联的实参,检查的项目包括实参是不是指针、指针类型和数组元素的类型是否匹配,但不会检查数组的长度。
voidprint(int*a[])
voidprint( int*a[10] )
voidprint( int*a )
上面两个都是二级指针,下面一个是一级指针
在很多情况下,将数组形参直接定义为指针要比使用数组语法定义方便很多。
因为定义为指针后,函数可以借助于指针方便的操作数组元素。
数组以非引用类型的传递时,此时数组会自动转换为同类型的指针,即初始化为相应类型实参的副本。
调用函数时,函数实际操作的是指针的副本,而不会修改实参指针的值,但是可以通过指针改变数组元素的值。
2多维数组的传递
多维数组的元素本身就是数组。
对二维数组的处理可以采用将二维数组看作一维或者二维数组来处理,下面两个例子分别采用了这两种方法。
第3个例子有点不同,但实际上也是利用了一维数组作中间过渡处理。
例1将二维数组当作一维数组来处理:
//print_array和主函数中的循环printf实现了同样效果
#include
voidprint_array(int*p,intRowSize,intLineSize)
{
inti,j;
for(i=0;i { for(j=0;j printf("%d",*(p+i*LineSize+j)); printf("\n"); } } voidmain() { inti,j,a[3][3]={{1,0,0},{0,1,0},{0,0,1}}; print_array((int*)a,3,3); for(i=0;i<3;i++) { for(j=0;j<3;j++) printf("%d",*(*(a+i)+j)); printf("\n"); } } 例2将二维数组依旧当作二维数组来处理 下面是一个字符串数组的参数传递程序,实现将字符串数组中的字符串按照从小到大的顺序进行排序: //WordSort实现了对5个字符串的排序 #include"stdio.h" #include"stdlib.h" #include"string.h" voidWordSort(charp[][10],intRowSize) { intn=0,m; chartemp[10]; for(n=0;n for(m=n+1;m if(strcmp(p[m],p[n])<0) { strcpy(temp,p[n]); strcpy(p[n],p[m]); strcpy(p[m],temp); } for(n=0;n<5;++n) printf("Insubfunction: %s\n",p[n]); } voidmain() { intk=0; charword[5][10]; for(;k<5;++k) scanf("%s",&word[k]); WordSort(word,5); printf("sortedword: \n"); for(k=0;k<5;k++) printf("Inmainfunction: %s\n",word[k]); system("pause"); } 例3用“行指针”传递参数 运行下面程序: /************************************/ //二维数组作为形参的参数传递方式之一 /************************************/ #include voidprint_array_1(int(*a)[3],intRow_Size) { intj; for(j=0;j<3*Row_Size;j++) { printf("%d",(*a)[j]); if(j%3==2)printf("\n"); } } voidprint_array_2(int(*a)[3],intRow_Size) { inti,j; for(i=0;i { for(j=0;j<3;j++) printf("%d",*(*(a+i)+j)); printf("\n"); } } voidmain() { inti,j,value=0; inta[4][3]={0}; for(i=0;i<4;i++) for(j=0;j<3;j++) a[i][j]=value++; print_array_1(a,4); printf("\n"); print_array_2(a,4); } 这个程序中的两个函数实现了相同的功能: 打印数组元素。 这种方法可能容易使人迷惑: int(*a)[3]是什么东西呢? 还得看强哥的书(P229-P230),上面这样写道(在本例中): *a有3个元素,每个元素为整型。 也就是a所指向的对象是有3个整型元素的数组,即a是行指针。 再强调一遍int(*a)[3]中括号的作用,如果不明白它的重要性,请仔细对比本文章黄色背景的代码。 补充一点,用这个方法处理字符串数组(字符型二维数组),还是比较方便的: 用这样一个例子结束本文: //打印数组内字符串(一行) #include voidprint_string(char(*string)[20],intRow_Size) { inti; for(i=0;i printf("%s\n",string+i); } voidmain() { chara[6][20]={"God","bless","you","who","help","themselves"}; print_string(a,6); } 数组,指针 随笔-11 文章-0 评论-16 关于int*a;int&a;int&*a;int*&a 上述的四条语句,前面两个很好理解,而后面两个,大部分C++初学者都会比较困惑,今天我也是查阅了一些资料以后才恍然大悟。 下面具体来说明一下: inti; int*a=&i;//这里a是一个指针,它指向变量i int&b=i;//这里b是一个引用,它是变量i的引用,引用是什么? 它的本质是什么? 下面会具体讲述 int*&c=a;//这里c是一个引用,它是指针a的引用 int&*d;//这里d是一个指针,它指向引用,但引用不是实体,所以这是错误的 数组和指针参数是如何被编译器修改的? “数组名被改写成一个指针参数”规则并不是递归定义的。 数组的数组会被改写成“数组的指针”,而不是“指针的指针”: 实参 所匹配的形参 数组的数组 charc[8][10]; char(*)[10]; 数组指针 指针数组 char*c[10]; char**c; 指针的指针 数组指针(行指针) char(*c)[10]; char(*c)[10]; 不改变 指针的指针 char**c; char**c; 不改变 #include"stdafx.h" #include usingnamespacestd; int_tmain(intargc,_TCHAR*argv[]) { intarr1[3]; intarr2[3]; intarr3[3]; int*ptr; //ptr1是一个指向int[3]的指针,即ptr的类型和&arr1的类型是一样的,注意: arr1指向的内存区域定长 intptr1[3][3]={{1,2,3},{1,2,3},{1,2,3}}; //ptr2是一个指向int*的指针,即ptr2的类型和&ptr是一样的,注意: ptr指向的内存区域不定长 int*ptr2[3]={arr1,arr2,arr3}; //ptr3是一个指向int[3]的指针,即ptr3的类型和&arr1的类型是一样的,注意: arr1指向的内存区域定长 int(*ptr3)[3]=&arr1; ptr3=ptr1;//没错,他们的类型相同 //ptr3=ptr2;//error无法从“int*[3]”转换为“int(*)[3] //ptr4是一个指向int*的指针,即ptr4的类型和&ptr是一样的,注意: ptr指向的内存区域不定长 int**ptr4; //ptr4=&arr1;//error无法从“int(*)[3]”转换为“int** ptr4=ptr2;//没错,他们的类型相同 //ptr4=ptr3;//error无法从“int(*)[3]”转换为“int** return0; } n个人的生日不重复的概率是P=N! /(N^n*(N-n)! ),其中N=365,一年的天数。 根据这个公式就可以解决第一问; 写程序模拟: for(intm=0;m<要统计几次;i++) { for(inti=0;i<人数;i++) { 生日[i]=rand()*N+1;//产生1-365的数 } //判断生日数组里的数是否重复 记录不重复的次数 } 最后,不重复的次数除以要统计的次数就是计算机模拟生日不重复的概率。 以上是方法,代码就自己写吧,不难写 importjava.util.HashSet; importjava.util.Set; publicclassIsRepeated{ publicstaticvoidmain(String[]arg){ System.out.println(isRepeated2(newint[]{1,2,3,4,5,5})); } publicstaticbooleanisRepeated(int[]nums){ booleanflag=false; for(inti=0;i for(intj=i+1;j if(nums[i]==nums[j]){ flag=true; break; } } } returnflag; } publicstaticbooleanisRepeated2(int[]nums){ booleanflag=false; Set for(inti=0;i if(! set.add(nums[i])){ flag=true; break; } } returnflag; } } hao192012-01-09 1、c++中也可以用printf格式输出。 2、包含了iomanip头文件,cout也能格式输出。 具体看: #include 这里面iomanip的作用比较多: 主要是对cin,cout之类的一些操纵运算子,比如setfill,setw,setbase,setprecision等等。 它是I/O流控制头文件,就像C里面的格式化输出一样.以下是一些常见的控制函数的: dec置基数为10相当于"%d" hex置基数为16相当于"%X" oct置基数为8相当于"%o" //作用永久 sample: cout<<12< setprecision(n)设显示小数精度为n位//作用永久 sample: setf(ios: fixed); cout< (2)<<2.345< : fixed);否则结果自己测试下 setw(n)设域宽为n个字符//作用临时 这个控制符的意思是保证输出宽度为n。 如: cout< 110100(默认是右对齐)当输出长度大于3时(<<1000),setw(3)不起作用。 setfill(c)设填充字符为c setioflags(ios: : fixed)固定的浮点显示 setioflags(ios: : scientific)指数表示 samplecout< : fixed)< (2)<<2.345< setiosflags(ios: : left)左对齐 setiosflags(ios: : right)右对齐 setiosflags(ios: : skipws)忽略前导空白 setiosflags(ios: : uppercase)16进制数大写输出 setiosflags(ios: : lowercase)16进制小写输出 setiosflags(ios: : showpoint)强制显示小数点 setiosflags(ios: : showpos)强制显示符号 sample: cout< : uppercase)< cout< : showpoint)< cout< : showpos)<<1< #include usingnamespacestd; classFenShu { public: FenShu(intFen_Zi=1,intFen_Mu=1); voidadd(constFenShu&a); voidshow(); intFenzi(){returnFenZi;} intFenmu(){returnFenMu;} intGCD(intFenZi,intFenMu); friendFenShuoperator+(FenShu&a,const
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 语言 二维 数组