1、c语言二维数组关于二维数组传参做形参 分类: Linux C 基础 今天开始嵌入式 2011-08-26 19:06 10773人阅读 评论(3) 收藏 举报 编译器stringfunctionsystem存储二维数组的存储方式是和一维数组没什么区别,但是用二维数组做参数,它的形参该怎样写?要注意的是:函数中的形参其实就相当于一个声明,并不产生内存分配,形参的目的就是要让编译器知道函数参数的数据类型。正确的是:void Func(int array310);void Func(int array10);可以省略第一维的大小错误的是void Func(int array.这样的用法只能在初始化时
2、可以用);这样写也是错误:void Func(const int m,const int n,int arraymn);或void Func(int m,int n,int arraymn);大家都知道数组的索引必须是个常量表达式,void Func(const int m,const int n,int arraymn);如果const int m没有初始化,那么系统将m或n自动初始化为0,所以这样些是不对的如果我们采用这样void Func(int *array, int m, int n)的形式,那么在实际的函数调用是,我们就要进行强制转换才可以用,我们可以这样调用void Func(i
3、nt *)array, int m, int n);在函数调用时,要把数组形式写成指针形式如*(int*)array + n*i + j);直接写int arrayij会导致错误,编译可以通过,在VC编译器中执行会出现异常,DEV编译器会出现一个随机值,原因就在于如果写成int arrayij,编译器无法正确的寻址,当然各种编译器对它的处理结果是不一样的。如果我们的形参是数组,那么我们在函数体中可以用指针也可以用数组形式,但是如果我们形参数中用的是指针,最好也用指针,有时用数组形式会出错,二维数组就是这样=以下是网上摘抄的一段:首先,我引用了谭浩强先生编著的C程序设计上面的一节原文,它简要介绍
4、了如何将二维数组作为参数传递,原文如下(略有改变,请原谅):原文开始可以用二维数组名作为实参或者形参,在被调用函数中对形参数组定义时可以指定所有维数的大小,也可以省略第一维的大小说明,如:void Func(int array310);void Func(int array10);二者都是合法而且等价,但是不能把第二维或者更高维的大小省略,如下面的定义是不合法的:void Func(int array);因为从实参传递来的是数组的起始地址,在内存中按数组排列规则存放(按行存放),而并不区分行和列,如果在形参中不说明列数,则系统无法决定应为多少行多少列,不能只指定一维而不指定第二维,下面写法是错
5、误的:void Func(int array3);实参数组维数可以大于形参数组,例如实参(zhihui3409注:应该是形参)数组定义为:void Func(int array310);而形参(zhihui3409注:应该是实参)数组定义为:int array510;这时形参数组只取实参数组的一部分,其余部分不起作用。原文结束大家可以看到,将二维数组当作参数的时候,必须指明所有维数大小或者省略第一维的,但是不能省略第二维或者更高维的大小,这是由编译器原理限制的。根据编译原理可知,如果我们省略了第二维或者更高维的大小,编译器将不知道如何正确的寻址。但是我们在编写程序的时候却需要用到各个维数都不固
6、定的二维数组作为参数,这就难办了,编译器不能识别啊,怎么办呢?不要着急,编译器虽然不能识别,但是我们完全可以不把它当作一个二维数组,而是把它当作一个普通的指针,再另外加上两个参数指明各个维数,然后我们为二维数组手工寻址,这样就达到了将二维数组作为函数的参数传递的目的,根据这个思想,我们可以把维数固定的参数变为维数随机的参数,例如:void Func(int array310);void Func(int array10);变为:void Func(int *array, int RowSize, int LineSize);在转变后的函数中,arrayij这样的式子是不对的(不信,大家可以试一
7、下),因为编译器不能正确的为它寻址,所以我们需要模仿编译器的行为把arrayij手工转变为:*(int*)array + LineSize*i + j);即把二维数组当作一维数组来处理,这是比较容易理解的方式。其它方式见下面总结的第二点。数组作为形参的问题总结:1 一维数组作为函数形参数组作为形参时,编译器通常只会检查数组形参关联的实参,检查的项目包括实参是不是指针、指针类型和数组元素的类型是否匹配,但不会检查数组的长度。void print( int *a )void print(int *a10)void print(int *a)上面两个都是二级指针,下面一个是一级指针在很多情况下,将数
8、组形参直接定义为指针要比使用数组语法定义方便很多。因为定义为指针后,函数可以借助于指针方便的操作数组元素。数组以非引用类型的传递时,此时数组会自动转换为同类型的指针,即初始化为相应类型实参的副本。调用函数时,函数实际操作的是指针的副本,而不会修改实参指针的值,但是可以通过指针改变数组元素的值。2 多维数组的传递多维数组的元素本身就是数组。对二维数组的处理可以采用将二维数组看作一维或者二维数组来处理,下面两个例子分别采用了这两种方法。第3个例子有点不同,但实际上也是利用了一维数组作中间过渡处理。例1 将二维数组当作一维数组来处理: /print_array和主函数中的循环printf实现了同样效
9、果 #include void print_array(int *p,int RowSize,int LineSize) int i,j; for(i=0 ; iRowSize ;i+) for(j=0 ; jLineSize ;j+) printf(%d ,*(p+i*LineSize+j); printf(n); void main() int i,j,a33= 1,0,0 , 0,1,0 , 0,0,1 ; print_array( (int *)a ,3,3); for(i=0;i3;i+) for(j=0;j3;j+) printf(%d ,*(*(a+i)+j); printf(n
10、); 例2 将二维数组依旧当作二维数组来处理下面是一个字符串数组的参数传递程序,实现将字符串数组中的字符串按照从小到大的顺序进行排序: /WordSort实现了对5个字符串的排序 #include stdio.h #include stdlib.h #include string.h void WordSort(char p10,int RowSize) int n=0,m; char temp10; for(n=0;nRowSize;n+) for(m=n+1;mRowSize;m+) if( strcmp(pm,pn) 0 ) strcpy(temp,pn); strcpy(pn,pm);
11、 strcpy(pm,temp); for(n=0;n5;+n) printf(In subfunction:%sn,pn); void main() int k=0; char word510; for(;k5;+k) scanf(%s,&wordk); WordSort(word,5); printf(sorted word:n); for(k=0;k5;k+) printf(In main function:%sn,wordk); system(pause); 例3 用“行指针”传递参数运行下面程序: /*/ /二维数组作为形参的参数传递方式之一 /*/ #include void pr
12、int_array_1(int (*a)3, int Row_Size) int j; for(j=0;j3*Row_Size;j+) printf(%d ,(*a)j); if(j%3=2) printf(n); void print_array_2(int (*a)3, int Row_Size) int i,j; for(i=0;iRow_Size;i+) for(j=0;j3;j+) printf(%d ,*(*(a+i)+j); printf(n); void main() int i,j,value=0; int a43=0; for(i=0;i4;i+) for(j=0;j3;j
13、+) aij=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 中括号的作用,如果不明白它的重要性,请仔细对比本文章黄色背景的代码。补充一点,用这个方法处理字符串数组(字符型二维数组),还是比较方便的:用这样一个例子结束本文: /打印
14、数组内字符串(一行) #include void print_string(char (*string)20, int Row_Size) int i; for(i=0;iRow_Size;i+) printf(%sn,string+i); void main() char a620=God,bless,you,who,help,themselves; print_string(a,6); 数组,指针随笔- 11 文章- 0 评论- 16 关于int *a; int &a; int & *a; int * &a 上述的四条语句,前面两个很好理解,而后面两个,大部分C初学者都会比较困惑,今天我也
15、是查阅了一些资料以后才恍然大悟。下面具体来说明一下:int i;int *a = &i;/这里a是一个指针,它指向变量iint &b = i;/这里b是一个引用,它是变量i的引用,引用是什么?它的本质是什么?下面会具体讲述int * &c = a;/这里c是一个引用,它是指针a的引用int & *d;/这里d是一个指针,它指向引用,但引用不是实体,所以这是错误的数组和指针参数是如何被编译器修改的?“数组名被改写成一个指针参数”规则并不是递归定义的。数组的数组会被改写成“数组的指针”,而不是“指针的指针”:实参 所匹配的形参数组的数组 char c810;char (*)10; 数组指针指针数组
16、 char *c10;char *c; 指针的指针数组指针(行指针) char (*c)10;char (*c)10; 不改变指针的指针 char *c; char *c; 不改变#include stdafx.h #include using namespace std; int _tmain(int argc, _TCHAR* argv) int arr13; int arr23; int arr33; int * ptr; / ptr1是一个指向 int 3 的指针,即ptr的类型和&arr1的类型是一样的,注意:arr1指向的内存区域定长 int ptr133=1,2,3,1,2,3,
17、1,2,3; / ptr2是一个指向 int * 的指针,即ptr2的类型和&ptr是一样的,注意:ptr指向的内存区域不定长 int * ptr23=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
18、 * ptr4; /ptr4=&arr1; /error 无法从“int (*)3”转换为“int * ptr4=ptr2; / 没错,他们的类型相同 /ptr4=ptr3; / error 无法从“int (*)3”转换为“int * return 0; n个人的生日不重复的概率是P=N!/(Nn*(N-n)!),其中N=365,一年的天数。根据这个公式就可以解决第一问;写程序模拟:for(int m=0;m要统计几次;i+)for(int i=0;i人数;i+) 生日i=rand()*N+1; /产生1-365的数/判断生日数组里的数是否重复记录不重复的次数最后,不重复的次数除以要统计的次
19、数就是计算机模拟生日不重复的概率。以上是方法,代码就自己写吧,不难写import java.util.HashSet;import java.util.Set;public class IsRepeated public static void main(String arg) System.out.println(isRepeated2(new int 1, 2, 3, 4, 5, 5 ); public static boolean isRepeated(int nums) boolean flag = false; for (int i = 0; i nums.length; i+) f
20、or (int j = i + 1; j nums.length; j+) if (numsi = numsj) flag = true; break; return flag; public static boolean isRepeated2(int nums) boolean flag = false; Set set = new HashSet(); for(int i = 0; i nums.length; i+) if(!set.add(numsi) flag = true; break; return flag; hao19 2012-01-09 1、c+中也可以用printf格
21、式输出。2、包含了 iomanip头文件,cout也能格式输出。具体看:#include 这里面iomanip的作用比较多:主要是对cin,cout之类的一些操纵运算子,比如setfill,setw,setbase,setprecision等等。它是I/O流控制头文件,就像C里面的格式化输出一样.以下是一些常见的控制函数的:dec 置基数为10 相当于%dhex 置基数为16 相当于%Xoct 置基数为8 相当于%o /作用永久sample:cout12hex12oct1212;output 12c1414setprecision(n) 设显示小数精度为n位 /作用永久sample:setf(
22、ios:fixed);coutsetprecision(2)2.345endl; ouput 2.34 /注意先用setf(ios:fixed);否则结果自己测试下setw(n) 设域宽为n个字符 /作用临时这个控制符的意思是保证输出宽度为n。如:coutsetw(3)1setw(3)10setw(3)100; 输出结果为1 10100 (默认是右对齐)当输出长度大于3时(1000),setw(3)不起作用。setfill(c) 设填充字符为csetioflags(ios:fixed) 固定的浮点显示setioflags(ios:scientific) 指数表示 sample coutseti
23、osflags(ios:fixed)setprecision(2)2.345endl; output 2.34setiosflags(ios:left) 左对齐setiosflags(ios:right) 右对齐setiosflags(ios:skipws) 忽略前导空白setiosflags(ios:uppercase) 16进制数大写输出setiosflags(ios:lowercase) 16进制小写输出setiosflags(ios:showpoint) 强制显示小数点setiosflags(ios:showpos) 强制显示符号sample: coutsetiosflags(ios:
24、uppercase)hex1215endl; output CFcoutsetioflags(ios:showpoint)xendl;若float x=1,则output 1.000000 不使用直接输出1coutsetiosflags(ios:showpos)1endl;output +1#include using namespace std;class FenShupublic:FenShu(int Fen_Zi = 1, int Fen_Mu = 1);void add(const FenShu & a);void show();int Fenzi()return FenZi;int Fenmu()return FenMu;int GCD(int FenZi,int FenMu);friend FenShu operator+(FenShu & a,const