二维数组
我们以前学过的数组叫一维数组(只有一行)
二维数组,有行有列
0 1 2 3
0 1 2 3 4
1 5 6 7 8
2 9 10 11 12
如何来定义二维数组
格式:类型标识符数组名[行的长度][列的长度];
Int a[3][4] 讨论一下究竟有多少元素?元素个数=行的长度*列的长度意义:定义了一个二维数组名为A含有12个元素,每个元素都是一个整形变量,他们是:
a[0][1],a[0][2]…对于第一行而言,行的下标都是零。
规律:对于每一行而言,行的下标不会改变,列的下标改变。
给二维数组赋初值(实际上是给二维数组中的每个元素付出只)1)int a[3][4]={1,2,3,4, 5,6,7,8, 9,10,11,12} ; 必须要会认,最基本的,比如a[2][0],分组后是9
2)int a[3][4]={1,2,3,4},{5,6,7,8}{9,10,11,12};
3)可以省略行,但不能省略列
A:iint a[][4]= {1,2,3,4, 5,6,7,8, 9,10,11,12} ;
B:int a[][4] ={1,2,3,4},{5,6,7,8}{9,10,11,12};
4) int a[3][4]={1,2,3,4, 5,6,7,8, 9,10,11} ;可以少赋值,自动填0
a[2][3]=0
5) int a[][4] ={1,3,4},{5,6,7,8}{9,10,11,12}; a[0][3]=0
注意:
1)二维数组的复制原则,是要优先满足前面的行,然后再来满足后面的行
2)二维数组行的长度用来表明共有多少行,列的个数用来表明每行的元素个数
二维数组的输出
1)有数组就要循环
我们肯定要输出三行,每行要输出四个数据
第i行第j个元素:for(i=0;i<3(行的长度);i++)
{for(j=0;j<4(列的长度);j++)
{printf(“%d”,a[i][j]);}//如果内循环做完了,表示第i行
就输出完了
printf(“/n”);}
一维字符型数组
Char a[5]这个数组含有五个元素,每个元素都是一个字符型变量。如何来定义一维字符型数组
Char 数组名[长度]
Char a[5]定义了一个数组a,它里面含有五个元素,每个变量都是字符型
如何赋初值
1)一维字符型数组从整体上看就是一个字符串,每一个元素还是字符Char a[5] abcde 思考:是挨在一起存储,还是分开存储?
答:既然是数组,就会挨在一起存储,就是一个字符串。
2)关于字符串的结束符号/0
A:\0虽然有两个字符,但就是一个字符,不是字符串
是’\0’,不是“\0”
B:每当C程序在用到字符串时,C就会偷偷在字符串的最后加上一个结束标记\0,用户是看不到的
C:用户可以根据需要在字符串的任意位置加上\0
D:\0告诉C程序字符串到此为止
3)char a[5]={‘a’,’b’,’c’,’d’,’e’};(错误的) char a[5]={‘a’,’b’,’c’,’d’ };
至少应该留一个空位来存放\0
Char a[5]={“abcd”}
Char a[]={“asdfghjkj”}像气球一样想吹多大吹多大(用的最多)
Char a[]=“asdfghjkj”
一维字符数组的输入和输出
输出:
A:分别输出for(i=0;i B:整体输出 1)格式:Puts(数组名);只有对字符型数组才可以用puts,整实型数组输出的唯一方法是分别输出 2)printf(“%s”,数组名); 区别:puts可以换行,printf不能换行 Eg:Char a[]={“asdf”},b[]={“asdf”}; Printf(“%s”,a); Printf(“%s”,b); //结果是asdfasdf Puts(a); Puts(b); //结果是asdf asdf 输入: 1)整体输入:scanf(“%s”,数组名)不要加取地址符 2)gets(数组名) 注意:scanf不能输入空格,会被当成\0; gets可以输入任何字符,尽量采用gets 如果是对于一维数组而言,他们的输入方式一般用整体输入输出,而其他数组只能分别输入和输出 函数 什么是函数? 特征:1)必须要完成某个功能功能2)函数必须要有名字 3)为了完成某个功能的代码段(块) 为什么要使用函数? 一个公司的发展与壮大 1,是不是只有老板一个人(团队合作) 财务部、销售部、公关部、策划部(各负其责,分工) 2,学校:校长,主任,教师,学生(分工) 生产流水线,先分工再整合 答案:是为了实现模块化设计(分工) 函数的分类 1)按照功能分类: 1.系统函数(标准函数):是C已经做好的函数,直接拿来使用即可,我们不了解函数的实现代码。比如printf函数,不需要知道它的工作原理,因为那不是用户的任务,用户的任务是使用。 2.用户自定义函数:系统函数虽然不需要用户做,但是系统函数的功能毕竟是有限的,为了得到功能更强大的函数,所以需要用户自己编写一些函数。 2)按有无参数分类: 1.有参函数:printf(“123456”); 2.无参函数:getchar(); 总结:系统函数:有参数,无参数 无参函数:有参数,无参数 如何定义函数? 1,无参数的定义格式: Void 函数名() { 代码} 说明:A:函数名可由用户自取,与变量名一致但要符合C程序的语法规则 B:无参函数括号里什么都不写,但是括号必须写 C:函数要先定义在使用,如果只定义不使用没有意义,不定义就是用是错误的。 D:一个程序中,可以有多个自定义函数,但是main函数有且仅有一个(老大只有一个,小弟可以很多) E:一般是在main函数中调用用户自定义函数。 F:一般都是把用户自定函数写在上边,而把用户自定义函数写在最下边 G:程序永远都是从main函数开始执行,在main函数中如果遇到用户自定义函数,流程回马上转到用户自定义函数执行,执行完成后在转到main函数 H:使用函数可以实现代码重用。 比如:void p() (只是在定义函数(生产),并不是在使用函数(使用)) { printf(“*****\n”); } 无参函数的使用(术语:调用) 格式:函数名() #include”studio.h” Void p() //以后p就代表这两行星 {printf(“*******”); printf(“*******”);} main() { p(); } //是main函数在调用p函数 分工,main只是调用p,*是p打印的。 Eg:编写一个程序,打印出: ************ Hello! Hello! Hello! Hello! ************ #include”studio.h” Void a() {printf(“************\n”);} Void b() {printf(“H ello! Hello! Hello! Hello!”)} Main() {a();b();a();} 很酷 Eg:编写一个程序,找出所有的水仙花数,它是一个三位数,各个位上的立方之后等于这个数本身。153=1+125+27 1.变量:每个位共三个,立方和一个,数值一个。共五个 2.算法分析:1)数位变量:int a[9]={1,2,3,4,5,6,7,8,9}, b[10]={1,2,3,4,5,6,7,8,9,0}, c[10]={1,2,3,4,5,6,7,8,9,0}; 2)求和:定义s1变量,为了不失一般性s1=a[i]*100+b[j]*10+c[k]; 3)立方和:定义s2变量,s2= a[i]* a[i]* a[i]+ b[j]* b[j]* b[j]+ c[k]* c[k]* c[k]; 3.代码: #include”studio.h” Main() { Int a[9]={1,2,3,4,5,6,7,8,9},b[10]={1,2,3,4,5,6,7,8,9,0}, c[10]={1,2,3,4,5,6,7,8,9,0},s1,s2,i,j,k; for(i=0;i<9;i++) for(j=0;j<9;j++) for(k=0;k<9;k++) { s1=a[i]*100+b[j]*10+c[k]; s2= a[i]* a[i]* a[i]+ b[j]* b[j]* b[j]+ c[k]* c[k]* c[k]; if(s1!=s2) printf(“%5d”,s1); } } 遍历所有的三位数,分离出来十位个位百位,之后进行判断。 #include”studio.h” Void flower() { Int i,s,a,b,c; For(i=100;i<1000;i++) { a=i/100; b=i/10%10; c=i%10; s=a*a*a+b*b*b+c*c*c; if(s!=i) printf(“%6d”,i); } } Main() { Flower(); Eg:编写一个程序,打印以下图形: ***** *** * * *** ***** ***** *** * * *** ***** 变量:i,j,k, Viod top() { Printf(“*****\n”); Printf(“***\n”); Printf(“*\n”); } Void bottom() { Printf(“*\n”); Printf(“***\n”); Printf(“*****\n”); } Main() { Top(); Bottom(); Top(); Bottom() } 有参函数的定义及使用有参函数的定义: 格式:类型标识符(参数列表) 代码;(在处理) Return 处理的结果 } Int sum(int a,int b) [] { int s;//没有写在括号里,不是参数,s是在函数里面帮忙的 S=a+b; Return s;//表示返回 } 1.sum函数他的功能是为了求出两个整数的和 2.sum函数需不需要数据支持?需要ps:如F(x,y)=x+y 1)在定义函数时,写在参数列表括号中的变量被称为参数 2)可见函数的参数依然是变量 3)虽然参数是变量但是在定义时即使类型相同也要分别定义,而且参数与参数之间要用逗号隔开。 4)函数为什么要有参数? 1.绞肉机有功能:把肉搅碎 2.数据支持:需要用户(外界)向它提供肉, 绞肉机不能自己为自己提供肉 空调,有功能降低温度。但是需要用户外界向它提供电量 A:函数都是为了完成某种功能 B:既然函数要完成功能的话,需要数据支持 C: 函数不能自己为自己提供数据,就需要向外界获取数据 D:而函数正是通过参数向外界获取数据的 E:在定义时要写在括号里面,而不是函数里面 总结:函数的参数是函数与外界发生数据交换的一个纽带 5)函数类型;是函数处理之后结果的类型 6)函数在处理完之后,会有一个结果,函数不能自己把结果消化掉,return语句来把处理之后的结果返回给外界。 格式:return 处理结果; 7)参数类型与函数类型没有任何关系 有参函数的应用举例 一般都是在main函数中使用 格式:变量名=函数名(值列表) 注意:1)对于有return 语句的函数而言,这些函数都会返回值,也就是说在调用时会得到一个值。为了把这个量接过来,所以就应该用一个变量保存起来。 2)调用一个有return 语句的函数 Eg:编写一个程序,他的目的是为了求出三个整数的最大值 算法分析:这个函数的功能是求最大值。 这个函数需要数据支持,三个参数,类型为整形。 处理之后有结果(最大值)函数类型为整形。 #include”studio.h” Int max(int a,int b,int c) { int m;//不是参数,是帮助max进行运算的 m=a; if(m if(m return m; } //所谓一次赋值两次比较 Main() { int k,a,b,c;//k不能用max代替,因为max是函数名,可以定义m printf(“请输入三个整数”); scanf(“%d,%d,%d”,&a,&b,&c);//变量名不一定要与参数一致,可以定义 别的 K=max(a,b,c);//可以bac cab .etc Printf(“k=%d”,k); }//求最大值的功能是由max函数完成的,赋值在 main里 2)编写一个函数,目的是求出1-n的和 累加算法,需要循环语句 N个数,所以参数只需要n一个 Int sum(int n) {int I,s; For(i=0;i S+=I; Return s; } Main() { } 3)编写一个函数,求整数n上的各个位上的数字之和; 这个函数只需要一个参数n来支持,函数类型也是整形 Int sum(int n) { intS=0; } 函数的形参与实参,调用方式(之一) 关于函数注意以下几点 1)在一个程序中可以有多个函数,但是main函数只能有一个 2)函数不能嵌套定义但是可以嵌套调用 3)如果一个函数的类型是整形,函数类型可以省略不写 如max(int a,int b) 4)函数类型是函数处理结果返回值的类型,如果返回值类型与函数类型不一致,那么应该以函数类型为准 Fun(float x,float y) {float s; S=x+y; Return s; } Main() {float x=1.4,y=2.5; Printf(“%d”,fun(x,y)); }结果是3 5)一个函数可以有多个return语句,最先遇到哪一个return语句,就从该处结束函数调用,返回 Fun(int x,int y) { If(x>y) { X++;//6 Y+=x;//9 Return x;//返回6,类似循环的break } Y++; Return x+y; } Main() {float x=5,y=3; Printf(“%d”,fun(x,y)); }结果是6 Max(int a,int b) {int m; If(a>b) m=a; Else m=b; Return m;} 更简洁的代码:if(a>b) return a;return b; 6)一个函数也可以没有return语句,但这并不意味着函数不返回值,函数会返回一个不确定的值。 Fun(int a) {int I; For(i=0;I Printf(“*”); N++; } 7)一个函数里面即使没有return语句这个函数也会返回值 8)可以把函数类型改为“void”,这样就能保证函数一定不返回值,既然不能返回值了(再写return就会出错),在调用时,就不能把值付给变量 9)一个函数类型如果是void A:函数在定义时,不能写return语句 B:不能在调用时把调用的结果赋给变量,不能写“变量名=函数名”只能写:“函数名(值)” 10)函数当然可以没有返回值(void函数) A:在函数里面实现输出时(使用printf函数时) 编写一个函数,目的是为了输出n个* 功能是输出*,需要一个参数n,函数不能有运算结果,n个*不能算结果,叫图案 Void fun(int n) { Int I; For(i=0;i } Main() { Int n=10; Fun(n); } B:函数在执行某个动作 编写一个函数,把数组中每个元素都加1(+1叫动作),有所谓的返回值就是处理后的数组,但是数字不是一个结果,所以也不能成为结果。 11)判断一个函数是否有处理结果: A:是否有唯一的一个结果 B:这个结果必须是一个数字 函数的形参与实参,调用方式(之二) 1,这个函数是为了完成什么功能 2,要完成这个功能,需不需要数据支持(考察是否需要参数) 大部分函数都需要参数 3,完成这个功能有没有处理数据,考察有没有结果, 结果是否是唯一的 A:在处理,但是没有运算结果,或者运算结果不止一个,我们就应该不返回值。格式:void 函数名(参数){进行相应的处理,没有return 语句},在调用时“函数名(值)” ******************************** Eg:有参数的没有返回值的函数 编写一个程序,目的是为了打印出n行的* * *** ***** Etc…… 考察打印第i行*(屏幕共40个格) 先打印20-i个空格 Void fun(int n)//这里的n是形参 { int I,j; For(i=1;i<=n;i++) { For(j=1;j<=20-i;j++) Printf(“”); For(k=1;k<=2*i-1;k++) } Printf(“\n”) } Main() { Int n;//这里的n是实参 Scanf(“请输入一个整数”); Fun(n); } B:函数在执行某个动作 A:在函数里面实现输出时(使用printf函数时) ******************************** B,在处理,并且结果是唯一的,就应该返回值 格式:类型标识符函数名(参数) {进行相应的处理,一般要有返回值} 12)函数的形参与实参 形参:在定义函数时,写在函数参数列表中的变量 实参:在调用函数时,写在函数括号里的变量 关系:形参的改变不会影响实参 Eg: Viod fun(int n) { N++; (若加上printf(“%d\n”,n);答案是11\n10) } Main() { Int n=10;//n写成k一样成立,没有错误 Fun(n); Printf(“%d”,n) }结果是10,不是11, 13)函数形参与实参的对应关系是位置的关系,不是名称的关系 关于函数调用的三种方式 1)函数语句:把函数的调用做成为一个语句,用的最多的一种 2)函数表达式:把函数的调用做成一个表达式 Eg:int max(int a,int b) {if(a>b) Return a; Return b; } Main() {int a=1,b=2;//int s;s=max(a,b)*a+max(b,a)*b;printf(“%d”,s); Printf(“%d”,max(a,b));//printf是一个表达式,max(a,b)只是一个值} 3)函数参数:把一个函数调用的结果作为另外一个函数的参数Eg:int max(int a,int b) {if(a>b) Return a; Return b; } Int sum(n) {int I,s; for(i=0;i<=n;i++) s+=I; return s; } Main() { Int a=3,b=4,c=5; Save=sum(max(a,b) );\\所谓函数参数调用,最有特色 Printf(“%d”,save); [更酷的写法Printf(“%d”, sum(max(a,b) ));] } 更恶心的,比如:Printf(“%d”, max(max(a,b),max(a,c)) ); Printf(“%d”, max(max(max(b,c),b),max(a,c)) ); 二维数组 我们以前学过的数组叫一维数组(只有一行) 二维数组,有行有列 0 1 2 3 0 1 2 3 4 1 5 6 7 8 2 9 10 11 12 如何来定义二维数组 格式:类型标识符数组名[行的长度][列的长度]; Int a[3][4] 讨论一下究竟有多少元素?元素个数=行的长度*列的长度意义:定义了一个二维数组名为A含有12个元素,每个元素都是一个整形变量,他们是: a[0][1],a[0][2]…对于第一行而言,行的下标都是零。 规律:对于每一行而言,行的下标不会改变,列的下标改变。 给二维数组赋初值(实际上是给二维数组中的每个元素付出只)1)int a[3][4]={1,2,3,4, 5,6,7,8, 9,10,11,12} ; 必须要会认,最基本的,比如a[2][0],分组后是9 2)int a[3][4]={1,2,3,4},{5,6,7,8}{9,10,11,12}; 3)可以省略行,但不能省略列 A:iint a[][4]= {1,2,3,4, 5,6,7,8, 9,10,11,12} ; B:int a[][4] ={1,2,3,4},{5,6,7,8}{9,10,11,12}; 4) int a[3][4]={1,2,3,4, 5,6,7,8, 9,10,11} ;可以少赋值,自动填0 a[2][3]=0 5) int a[][4] ={1,3,4},{5,6,7,8}{9,10,11,12}; a[0][3]=0 注意: 1)二维数组的复制原则,是要优先满足前面的行,然后再来满足后面的行 2)二维数组行的长度用来表明共有多少行,列的个数用来表明每行的元素个数 二维数组的输出 1)有数组就要循环 我们肯定要输出三行,每行要输出四个数据 第i行第j个元素:for(i=0;i<3(行的长度);i++) {for(j=0;j<4(列的长度);j++) {printf(“%d”,a[i][j]);}//如果内循环做完了,表示第i行 就输出完了 printf(“/n”);} 完成下列程序代码 1、将二维数组(5行5列)的右上半部分置零。即: #include for(j=0;j<5;j++) { scanf("%d",&a[i][j]); } } int sum=a[0][0],x,y; for(i=0;i<5;i++) { for(j=0;j<5;j++) { if(sum main() { int a[3][3],i,j; for(i=0;i<3;i++) { for(j=0;j<3;j++) { scanf("%d",&a[i][j]); } } for(i=0;i<3;i++) { for(j=0;j<3;j++) { if(i==0||j==0) { printf("%d",a[i][j]); } } C语言中动态分配二维数组 在C中动态分配内存的,对于单个变量,字符串,一维数组等,都是很容易的。C中动态分配二维数组的方法,很少有C语言书中描述,我查找了有的C语言书中提到了一个方法:假定二维数组的维数为[M][N] 分配是可以这样: int **ptr=new int*[M]; //////这是先动态分配一个包含有M个指针的数组,即指先分配一个针数组 ///////////指针数组的首地址保存在ptr中 for(int i=0;i C语言知识点总结8【二维数组】 一、二维数组的定义 ●一个3行,4列的二维数组。其行号:0,1,2;其列号:0,1,2,3 ●最大下标的元素为a[2][3],没有a[3][4]这个元素 ●数组共有3行,每一行都是:4个元素的一维数组,每一行的数组名分别为:a[0],a[1],a[2] ●从整体看,任何一个二维数组都可以看成是一个一维数组,只不过其数组元素又是一个一维数 组。 ●二维数组定义同时若有初始化,可以省略行号不写:如int a[][3]={1,2,3,4,5,6};系统会按照数据 的个数,和规定的列数,来确定数据分几行? ●二维数组定义同时若有初始化,可以省略行号不写,但列号不能省略:如int a[3][ ]={1,2,3,4,5}; 系统无法按照数据的个数,和规定的行数,来确定数据分几列。 二、二维数组的存储及地址关系 二维数组在计算机中的存储是按行连续存储。先保存第一行,在第一行末尾开始存第二行,依此类推。 这里,a是a[0]的地址,a[0]是数组元素a[0][0]的地址,则a是地址的地址,即二级地址 三、 二维数组的初始化 1、 分行赋值:int a[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}}; 2、 不分行赋值:全部数据写在一个大括号内:int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12}; 3、 部分元素赋值 4、如果对全部元素赋初值,则第一维的长度可以不指定,但必须指定第二维的长度。 int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12}; 等价:int a[ ][4]={1,2,3,4,5,6,7,8,9,10,11,12}; 四、 二维数组的输出 五、 二维数组的输入 矩阵问题1.给一个二维数组A赋值如下数据: 2.输出以下5×5的矩阵 3.拐角矩阵 1)左上拐角 #include 2) 右下拐角 void main() { int i,j,k,n; printf("n : "); scanf("%d",&n); for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { if(i<=j) printf("%4d",n+1-j); else printf("%4d",n+1-i); } printf("\n"); } } 3) 左下拐角 1 2 3 1 2 2 1 1 #include 可以用二维数组名作为实参或者形参,在被调用函数中对形参数组定义时可以指定所有维数的大小,也可以省略第一维的大小说明,如: void Func(int array[3][10]); void Func(int array[][10]); 二者都是合法而且等价,但是不能把第二维或者更高维的大小省略,如下面的定义是不合法的: void Func(int array[][]); 因为从实参传递来的是数组的起始地址,在内存中按数组排列规则存放(按行存放),而并不区分行和列,如果在形参中不说明列数,则系统无法决定应为多少行多少列,不能只指定一维而不指定第二维,下面写法是错误的: void Func(int array[3][]);实参数组维数可以大于形参数组,例如实参数组定义为: void Func(int array[3][10]); 而形参数组定义为: int array[5][10]; 这时形参数组只取实参数组的一部分,其余部分不起作用。 对于数组int p[m][n]; 如果要取p[i][j]的值(i>=0 && i 算法分析与设计课程论文 —通过C语言实现矩阵的相关操作 一.摘要 本文在Microsoft Visual Studio 2010的编译环境下,通过C语言进行一些矩阵的基本操作,包括矩阵的设置,加减乘除,数乘运算。求矩阵的逆等操作。 关键词 矩阵 C语言逆矩阵 二.正文 1.引言 矩阵的相关知识只是是高等数学的基础,但是其庞大的运算量和纷繁的步骤让人却步。虽然有Matlab等软件可以实现矩阵的相关操作,但是我校一些专业并不学习数学实验,故通过C语言实现矩阵的操作也是一种可行的方法,本文列举的了一些矩阵的加减乘除等基本运算规则,还有对矩阵进行转置,也有矩阵求逆的相关操作。 同时,还介绍了行列式的计算,通过运行该程序,可以大大简化行列式的计算量。 2.算法分析 矩阵的初始化 相关概念 在数学中,矩阵(Matrix)是一个按照长方阵列排列的复数或实数集合,最早来自于方程组的系数及常数所构成的方阵。这一概念由19世纪英国数学家凯利首先提出。 矩阵是高等代数学中的常见工具,也常见于统计分析等应用数学学科中。在物理学中,矩阵于电路学、力学、光学和量子物理中都有应用;计算机科学中,三维动画制作也需要用到矩阵。矩阵的运算是数值分析领域的重要问题。将矩阵分解为简单矩阵的组合可以在理论和实际应用上简化矩阵的运算。对一些应用广泛而形式特殊的矩阵,例如稀疏矩阵和准对角矩阵,有特定的快速运算算法。 理论分析 在C语言中,可以使用二维数组来描绘一个矩阵。值得注意的是,在二维数组中,必须标明列数,否则编译器就会报错。故二维极其多维数组使用时要注意数组下标。 代码实现 #include 前几日用C编写DSP程序时,遇到一个问题:如何向C函数中传递指向二维数组的指针参数。初接触以为很简单,直接声明一个二维数组,然后把数组名传进去。但是一经编译便报错。后来仔细想了一下,并查找了一些相关资料,发现二维数组在概念上远比一维数组复杂,或者说二维数组以一种晦涩的方式构建在一维数组之上。 先来回顾一下一维数组。一维数组的数组名即为指向该数组的指针,该指针值保存了数组存放在内存中的一块连续区域的起始地址;数组的下标表示了这片内存区域的某存储区相对于起始地址的偏移量。简单来讲就是:指向一维数组的指针,指向数据存放区域的起始位置。 事实上,计算机系统的多维数组其实最终还是以一维数组的形式实现的。就N x M的二维数组来讲,设其数组名为array。指针array 指向一个数组,该数组存放的是一系列指针,这些指针分别指向相应的一维数组,而这些数组中存放的才是我们的数据。 array -> [一维数组指针1] -> [ 一维数组,M长] [一维数组指针2] -> [ 一维数组,M长] …… …… [一维数组指针N] -> [ 一维数组,M长] 由此array是第i个指针变量地址,array[j]则表示相对于第i个指针变量偏移j*sizeof(数组类型)。系统通过这种机制访问了该二维数组的第i行,第j列的内容。 有上述可知,指向二维数组的指针其实是指向“指针变量地址”的指针变量。所以在声明指向二维数组的指针时,用int ** array的形式。 有以下两种方式来对二维数组分配内存: ///// 方法一 #include 在C中动态分配内存的,对于单个变量,字符串,一维数组等,都是很容易的。C中动态分配二维数组的方法,很少有C语言书中描述,我查找了有的C语言书中提到了一个方法: 假定二维数组的维数为[M][N] 分配是可以这样: int **ptr=new int*[M]; //////这是先动态分配一个包含有M个指针的数组,即指先分配一个针数组 ///////////指针数组的首地址保存在ptr中 for(int i=0;i { pMatrix[i] = new int[column]; for(int j = 0; j < column; j++) { pMatrix[i][j] = (i+j); ///////简单的初始化 } } 这样创建一个数组有个严重的问题,就是它的内存不连续,行与行之间的内存不连续,虽然可以用[i][j]下标访问,无法满足用指向二维数组元素型别的指针变量来访问整个数组的要求. 例如不能如下访问每个二维数组元素: int * p = NULL; for(p = pMatrix[0]; p < pMatrix[0]+column * row; p++) { int fff = *(pme); } 而这种访问方式对于真正的二维数组是完全可以的。出现这种原因就是因为行与行之间的内存不连续造成的。 所以,这中方式创建的动态二维数组,不是真正意义上的二维数组。 那么什么是真正的二维数组呢?C语言中的二维数组在内存组织形式是按行存储的连续的内存区域。所以,必须保证数组元素是按行存储的,而且也是最重要的是内存要连续。 所以,我写出了如下的一个方法: 假定二维数组的元素变量类型是MyType;可以是C语言接受的除void之外的任何类型,因为编译器不晓得void类型的大小;例如int,float,double等等类型; int row = 2; /////暂假定行数是2,这个可以在运行时刻决定; int column = 3;/////暂假定列数是2,这个可以在运行时刻决定; void **ptdhead = NULL; //////////在后面说明为什么要用void**类型 template getArray 上节讲解的数组可以看作是一行连续的数据,只有一个下标,称为一维数组。在实际问题中有很多量是二维的或多维的,因此C语言允许构造多维数组。多维数组元素有多个下标,以确定它在数组中的位置。本节只介绍二维数组,多维数组可由二维数组类推而得到。 二维数组的定义 二维数组定义的一般形式是: dataType arrayName[length1][length2]; 其中,dataType 为数据类型,arrayName 为数组名,length1 为第一维下标的长度,length2 为第二维下标的长度。例如:int a[3][4]; 定义了一个3行4列的数组,共有3×4=12个元素,数组名为a,即: a[0][0], a[0][1], a[0][2], a[0][3] a[1][0], a[1][1], a[1][2], a[1][3] a[2][0], a[2][1], a[2][2], a[2][3] 在二维数组中,要定位一个元素,必须给出一维下标和二维下标,就像在一个平面中确定一个点,要知道x坐标和y坐标。例如,a[3][4] 表示a数组第3行第4列的元素。 二维数组在概念上是二维的,但在内存中地址是连续的,也就是说存储器单元是按一维线性排列的。那么,如何在一维存储器中存放二维数组呢?有两种方式:一种是按行排列,即放完一行之后顺次放入第二行。另一种是按列排列,即放完一列之后再顺次放入第二列。 在C语言中,二维数组是按行排列的。也就是先存放a[0]行,再存放a[1]行,最后存放a[2]行;每行中的四个元素也是依次存放。数组a为int类型,每个元素占用4个字节,整个数组共占用4×(3×4)=48个字节。 【示例】一个学习小组有5个人,每个人有三门课的考试成绩。求全组分科的平均成绩和各科总平均成绩。 -- 张 王 李 赵 周 Math 80 61 59 85 76 C 75 65 63 C语言二维数组的定义和引用 7.1.1二维数组的定义 前面介绍的数组只有一个下标,称为一维数组,其数组元素也称为单下标变量。在实际问题中有很多量是二维的或多维的,因此C语言允许构造多维数组。多维数组元素有多个下标,以标识它在数组中的位置,所以也称为多下标变量。本小节只介绍二维数组,多维数组可由二维数组类推而得到。 二维数组定义的一般形式是:类型说明符数组名[常量表达式1][常量表达式2] 其中常量表达式1表示第一维下标的长度,常量表达式2 表示第二维下标的长度。例如:int a[3][4]; 说明了一个三行四列的数组,数组名为a,其下标变量的类型为整型。该数组的下标变量共有3×4个,即: a[0][0],a[0][1],a[0][2],a[0][3] a[1][0],a[1][1],a[1][2],a[1][3] a[2][0],a[2][1],a[2][2],a[2][3] 二维数组在概念上是二维的,即是说其下标在两个方向上变化,下标变量在数组中的位置也处于一个平面之中,而不是象一维数组只是一个向量。但是,实际的硬件存储器却是连续编址的,也就是说存储器单元是按一维线性排列的。如何在一维存储器中存放二维数组,可有两种方式:一种是按行排列,即放完一行之后顺次放入第二行。另一种是按列排列,即放完一列之后再顺次放入第二列。 在C语言中,二维数组是按行排列的。即,先存放a[0]行,再存放a[1]行,最后存放a[2]行。每行中有四个元素也是依次存放。由于数组a说明为int类型,该类型占两个字节的内存空间,所以每个元素均占有两个字节)。 7.1.2二维数组元素的引用 二维数组的元素也称为双下标变量,其表示的形式为: 数组名[下标][下标] 其中下标应为整型常量或整型表达式。例如: a[3][4] 表示a数组三行四列的元素。 下标变量和数组说明在形式中有些相似,但这两者具有完全不同的含义。数组说明的方括号中给出的是某一维的长度,即可取下标的最大值;而数组元素中的下标是该元素在数组中的位置标识。前者只能是常量,后者可以是常量,变量或表达式。 【例7.6】一个学习小组有5个人,每个人有三门课的考试成绩。求全组分科的平均成绩和各科总平均成绩。C语言笔记(二维数组-函数)
c语言二维数组课堂编程练习
C语言中动态分配二维数组
C语言知识点总结8【二维数组】
矩阵问题(c语言)讲解
C语言二维数组作为函数的参数
c语言实现矩阵的相关操作
如何在C函数中传递指向二维数组的指针参数
C语言中动态分配二维数组
C语言 二维数组的程序实现
C语言二维数组
C语言二维数组的定义和引用