二维数组定义以及动态分配空间(转)
下面三种定义形式怎么理解?怎么动态分配空间?
(1)、int **Ptr;
(2)、int *Ptr[ 5 ]; 我更喜欢写成int* Prt[5];
(3)、int ( *Ptr )[ 5 ];
此文引自网上,出处不详,但是觉得非常好。略改了一点。
多维数组一向很难,一般都采用一维数组,但是一旦要用到还真是头疼。
闲话少说,这里我就以三个二维数组的比较来展开讨论:
(1)、int **Ptr;
(2)、int *Ptr[ 5 ]; 我更喜欢写成int* Prt[5];
(3)、int ( *Ptr )[ 5 ];
以上三例都是整数的二维数组,都可以用形如Ptr[ 1 ][ 1 ] 的
方式访问其内容;但它们的差别却是很大的。下面我从四个方面对它们
进行讨论:
一、内容:
它们本身都是指针,它们的最终内容都是整数。注意我这里说
的是最终内容,而不是中间内容,比如你写Ptr[ 0 ],对于三者来说,
其内容都是一个整数指针,即int *;Ptr[ 1 ][ 1 ] 这样的形式才
是其最终内容。
二、意义:
(1)、int **Ptr 表示指向"一群"指向整数的指针的指针。
(2)、int *Ptr[ 5 ] 表示指向5 个指向整数的指针的指针,或者说Ptr有5个指向"一群"整数的指针,Ptr是这5个指针构成的数组的地址
(3)、int ( *Ptr )[ 5 ] 表示指向"一群"指向5 个整数数组的指针的指针。
三、所占空间:
(1)、int **Ptr 和(3)、int ( *Ptr )[ 5 ] 一样,在32位平台里,都是4字节,即一个指针。
但(2)、int *Ptr[ 5 ] 不同,它是5 个指针,它占5 * 4 = 20 个字节的内存空间。
四、用法:
(1)、int **Ptr
因为是指针的指针,需要两次内存分配才能使用其最终内容。首
先,Ptr = ( int ** )new int *[ 5 ];这样分配好了以后,它和(2)的
意义相同了;然后要分别对 5 个指针进行内存分配,例如:
Ptr[ 0 ] = new int[ 20 ];
它表示为第0 个指针分配20 个整数,分配好以后,Ptr[ 0 ] 为指
向20 个整数的数组。这时可以使用下标用法Ptr[ 0 ][ 0 ] 到
Ptr[ 0 ][ 19 ] 了。
如果没有第一次内存分配,该Ptr 是个"野"指针,是不能使用
的,如果没有第二次内存分配,则Ptr[ 0 ] 等也是个"野"指针,也
是不能用的。当然,用它指向某个已经定义的地址则是允许的,那是另外
的用法(类似于"借鸡生蛋"的做法),这里不作讨论(下同)。
例子:
C语言:
//动态分配二维数组空间
{
m_iHight=10;//二维数组的高度
m_i;//二维数组的宽度
//动态分配一个二维数组m_ppTable内存空间
//其类型为int
//m_ppTable指向该数组
int **m_ppTable;
m_ppTable=new int *[m_iHight];
//动态分配m_iHight个类型为int *的内存空间
//分配的是行地址空间
for(int i=0;i
m_ppTable[i]= new int[m_iWidth];
//动态分配m_iWidth个类型为int的内存空间
//分配的是某行的数值空间
}
//由此分配的二维数组空间并非是连续的
//可以使用m_ppTable[row][col]来给该二维数组赋值
//其中0<=row
//释放所分配的内存空间
{
for(int i=0;i
delete[m_iWidth]m_ppTable[i]; //以行为单位释放数值空间
delete [m_iHight]m_ppTable; //释放行地址空间
}
int **a;
a=(int **)calloc(sizeof(int *),n);
for (i=0;i a[i]=(int *)calloc(sizeof(int),n);
这样就可以了
使用的时候就和普通的二维数组一样
最后用
for(i=0;i cfree(a[i]);
cfree(a);释放内存
就可以了
(2)、int *Ptr[ 5 ]
这样定义的话,编译器已经为它分配了5 个指针的空间,这相当于(1)中的第一次内存分配。根据对(1)的讨论可知,显然要对其进行一次内存分配的。否则就是"野"指针。
(3)、int ( *Ptr )[ 5 ]
这种定义我觉得很费解,不是不懂,而是觉得理解起来特别吃力,
也许是我不太习惯这样的定义吧。怎么描述它呢?它的意义是"一群"
指针,每个指针都是指向一个 5 个整数的数组。如果想分配k 个指针,这样写:Ptr = ( int ( * )[ 5 ] ) new int[ 5 * k ]。
这是一次性的内存分配。分配好以后,Ptr 指向一片连续的地址空间,
其中Ptr[ 0 ] 指向第0 个 5 个整数数组的首地址,Ptr[ 1 ] 指向第
1 个5 个整数数组的首地址。
综上所述,我觉得可以这样理解它们:
int ** Ptr <==> int Ptr[ x ][ y ];
int *Ptr[ 5 ] <==> int Ptr[ 5 ][ x ];
int ( *Ptr )[ 5 ] <==> int Ptr[ x ][ 5 ];
这里x 和y 是表示若干的意思。
二维数组定义以及动态分配空间(转) 下面三种定义形式怎么理解?怎么动态分配空间? (1)、int **Ptr; (2)、int *Ptr[ 5 ]; 我更喜欢写成int* Prt[5]; (3)、int ( *Ptr )[ 5 ]; 此文引自网上,出处不详,但是觉得非常好。略改了一点。 多维数组一向很难,一般都采用一维数组,但是一旦要用到还真是头疼。 闲话少说,这里我就以三个二维数组的比较来展开讨论: (1)、int **Ptr; (2)、int *Ptr[ 5 ]; 我更喜欢写成int* Prt[5]; (3)、int ( *Ptr )[ 5 ]; 以上三例都是整数的二维数组,都可以用形如Ptr[ 1 ][ 1 ] 的 方式访问其内容;但它们的差别却是很大的。下面我从四个方面对它们 进行讨论: 一、内容: 它们本身都是指针,它们的最终内容都是整数。注意我这里说 的是最终内容,而不是中间内容,比如你写Ptr[ 0 ],对于三者来说, 其内容都是一个整数指针,即int *;Ptr[ 1 ][ 1 ] 这样的形式才 是其最终内容。 二、意义: (1)、int **Ptr 表示指向"一群"指向整数的指针的指针。 (2)、int *Ptr[ 5 ] 表示指向5 个指向整数的指针的指针,或者说Ptr有5个指向"一群"整数的指针,Ptr是这5个指针构成的数组的地址 (3)、int ( *Ptr )[ 5 ] 表示指向"一群"指向5 个整数数组的指针的指针。 三、所占空间: (1)、int **Ptr 和(3)、int ( *Ptr )[ 5 ] 一样,在32位平台里,都是4字节,即一个指针。 但(2)、int *Ptr[ 5 ] 不同,它是5 个指针,它占5 * 4 = 20 个字节的内存空间。 四、用法: (1)、int **Ptr 因为是指针的指针,需要两次内存分配才能使用其最终内容。首 先,Ptr = ( int ** )new int *[ 5 ];这样分配好了以后,它和(2)的 意义相同了;然后要分别对 5 个指针进行内存分配,例如: Ptr[ 0 ] = new int[ 20 ]; 它表示为第0 个指针分配20 个整数,分配好以后,Ptr[ 0 ] 为指 向20 个整数的数组。这时可以使用下标用法Ptr[ 0 ][ 0 ] 到 Ptr[ 0 ][ 19 ] 了。 如果没有第一次内存分配,该Ptr 是个"野"指针,是不能使用 的,如果没有第二次内存分配,则Ptr[ 0 ] 等也是个"野"指针,也 是不能用的。当然,用它指向某个已经定义的地址则是允许的,那是另外 的用法(类似于"借鸡生蛋"的做法),这里不作讨论(下同)。 例子:
二维数组的定义和引用 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类型,该类型占四个字节的内存空间,所以每个元素均占有四个字节)。
1.2二维数组元素的引用 二维数组的元素也称为双下标变量,其表示的形式为:数组名[下标][下标] 其中下标应为整型常量或整型表达式。 例如: a[3][4] 表示a数组三行四列的元素。 下标变量和数组说明在形式中有些相似,但这两者具有完全不同的含义。数组说明的方括号中给出的是某一维的长度,即可取下标的最大值;而数组元素中的下标是该元素在数组中的位置标识。前者只能是常量,后者可以是常量,变量或表达式。【例1】一个学习小组有5个人,每个人有三门课的考试成绩。 再设一个一维数组v[3]存放所求得各分科平均成绩,设变量average 为全组各科总平均成绩。编程如下: void main() { int i,j,s=0,average,v[3],a[5][3]; printf("input score\n"); for(i=0;i<3;i++) { for(j=0;j<5;j++) { scanf("%d",&a[j][i]); s=s+a[j][i];} v[i]=s/5; s=0;
C\C++程序设计复习题 一、选择题 1、一个C语言程序总是从( C )开始执行 A) 书写顺序的第一个函数 B) 书写顺序的第一条执行语句 C) 主函数main() D) 不确定 2、以下能正确定义二维数组的是( C ) A.int a[][3]; B.int a[][3]=2{2*3}; C.int a[][3]={}; D.int a[2][3]={{1},{2},{3,4}}; 3、设int x=3,y=4,z=5,则下列表达式中的值为0的是( D ) A) …x?&&?y?B) x||y+z&&y-z C) x<=y D) !((x A)5 B) 6 D) 7 D 9 9、若有定义,char *p=”computer”; 则语句printf(“%c”,*(p+2))运行结果是( B ) A) 随机值B) m C)o D) omputer 10、有以下程序( D ) main() { int i=0,x=0; for (;;) { if(i==3||i==5) continue; if (i==6) break; i++; s+=i; }; printf("%d\n",s); } 程序运行后的输出结果是 A.10 B.13 C.21 D.程序进入死循环 11、以下定义语句中正确的是( C ) A.char a='A'b='B'; B.float a=b=10.0; C.int a=10,*b=&a; D.float *a,b=&a; 12、设有int x=11;则表达式(x++*l/3)的值为( B )。 (A)3 (B)4 (C)11 (D)12 13、在说明一个结构体变量时系统分配给它的存储空间是( D ) A)该结构体中第一个成员变量所需存储空间B) 该结构体中最后一个成员变量所需存储空间 C)该结构体中占用最大存储空间的成员变量所需存储空间D) 该结构体中所有成员变量所需存储空间的总和 数组的元素也可以是数组,每个数组的一个元素都是由一个一维数组构成,被称为二维数组。同样,多维数组可以看作是数组的数组,即N维数组的每一个元素就是一个N-1维数组。如:三维数组中的每一个元素都是一个二维数组。多维数组的定义即初始化与二维数组的基本类似,因此本节主要讲述二维数组。 1 、二维数组的声明 二维数组声明的一般格式如下: 数据类型数组名[][]; 或者格式如下: 数据类型[][] 数组名; 其中数据类型与一维数组的相同,它既可以是基本数据类型,也可以是复合数据类型,数组名可以是任意合法的变量名。下面是数组声明举例。 char ch[][]; double[][] d; String[][] str; 与一维数组的声明相同,二维数组也不需要规定其中任意一维的长度,下面的声明都是不合法的。 char ch[4][]; double[][5] d; String[6][7] str; 2、二维数组的初始化 二维数组的初始化也分为直接初始化和动态初始化两种方式。直接初始化必须在声明时开始,如下 ··124面的例子所示。 int array[][] = {{1,2},{2,4},{4,8}}; 二维数组的动态初始化又可分为两种方式:一种是直接规定每一维的长度,并分配所需的内存空间,另一种是从高维开始,分别为每一维规定长度并分配内存空间。 直接为每一维分配内存的格式如下: 变量名= new 数据类型[二维长度][一维长度]; 其中二维长度和一维长度都是大于0的整数,如下所示。 int array[][]; array = new int[3][5]; array是一个二维数组,二维长度为3,array[0]、array[1]、array[2]都是一维数组,长度都是5。分别分配内存格式如下: 变量名= new 数据类型[二维长度][]; 变量名[0] = new 数据类型[一维长度0]; 变量名[1] = new 数据类型[一维长度1]; 变量名[2] = new 数据类型[一维长度2]; ... 变量名[二维长度-1] = new 数据类型[一维长度n]; 下面是一个二维数组初始化的实例。 Int array[][]; //声明int类型二维数组array A = new int[3][]; //为二维分配内存空间 A[0] = new int[5]; //为A[0]的一维分配内存空间 A[1] = new int[5]; //为A[1]的一维分配内存空间 A[2] = new int[5]; //为A[2]的一维分配内存空间 3、二维数组的空间模型 二维数组的动态分配与释放 1. C语言动态分配二维数组 (1)已知第二维 Code-1 char (*a)[N];//指向数组的指针 a = (char (*)[N])malloc(sizeof(char) * M*N); //注意M为数组的行,N为数组的列printf("%d\n", sizeof(a));//4,指针 printf("%d\n", sizeof(a[0]));//N*sizeof(char),一维数组 free(a); (2)已知第一维 Code-2 char* a[M];//指针的数组 int i; for(i=0; i 题目:定义一个一维数组存储10个学生名字;定义一个二维数组存储这10个学生的6门课(C程序设计、物理、英语、高数、体育、政治)的成绩; 程序应具有下列功能: (1)按名字查询某位同学成绩 (2)查询某个科目不及格的人数,及学生名单 代码如下: import java.util.*; public class Test{ public static void main(String[]args){ Scanner input=new Scanner(System.in); String[]name={"a","b","c","d","e","f","g","h","i","l"};//存储学生的名字 int[][] grade={{50,60,70,80,90,10},{40,90,80,60,40,70},{60,80,70,60,40,90},{50,60,70,80,90,10}, {60,80,70,60,40,90},{60,70,80,90,70,70},{60,80,70,60,40,90},{60,80,70,60,40,90},{70, 80,90,70,70,70},{60,80,70,60,40,90}};//存储学生各科成绩 System.out.println("输入要查询成绩的学生名字:"); String chioce=input.nextLine(); for(int i=0;i<10;i++) { if(name[i].equals(chioce)) {System.out.println("学生:"+name[i]+"的成绩如下:"); System.out.println("C程序设计:"+grade[i][0]+"物理:"+grade[i][1]+"英 语:"+grade[i][2]+"高数:"+grade[i][3]+"体育:"+grade[i][4]+"政治:"+grade[i][5]+"\n"); break;} } System.out.println("******************************************************"); C++定义动态数组 首先:为什么需要动态定义数组呢? 这是因为,很多情况下,在预编译过程阶段,数组的长度是不能预先知道的,必须在程序运行时动态的给出 但是问题是,c++要求定义数组时,必须明确给定数组的大小,要不然编译通不过 如:int Array[5];正确 int i=5; int Array[i]; 错误因为在编译阶段,编译器并不知道i 的值是多少 那么,我们该如何解决定义长度未知的数组呢? 答案是:new 动态定义数组 因为new 就是用来动态开辟空间的,所以当然可以用来开辟一个数组空间 这样,下面的语句: int size=50; int *p=new int[size]; 是正确的 但是二维动态数组能不能也这样定义呢 int size=50,Column=50; int (*p)[Column]=new int [size][Column] 这样的语句,编译器通不过,为什么呢? 首先new int[size][Column] 就是动态生成时确定的,所以它没有错 那么就是int(*p)[Column],这句有问题了,这句为什么不对呢,那是因为,这是一个定义语句,而定义语句先经过编译器进行编译,当编译器运行到此处时,发现Column 不是常数,因此不能通过编译。而之所以编译器认为Column 不是常数,是因为编译阶段,编译器起的作用是查语法错误,和预分配空间,它并不执行程序,因此,没有执行那个赋值语句(只是对这个语句检查错误,和分配空间),因此编译阶段,它将认为column 是个变量。所以上面的二维数组定义是错误的,它不能通过编译。 改成这样: int size=50 int (*p)[50]=new int [size][50] 便正确了。 由此可见,这种动态分配数组,仅对一维数组空间是真正动态分配的。 但是如何真正的动态分配二维数组呢,即如果Column 也不能预先知道的话,该如何处理呢? 上面的动态分配已经不能满足我们的要求,因为上面动态分配只对一维数组是真正动态的,对二维java数组之二维数组
二维数组的动态分配与释放
JAVA一维数组二维数组运用的例子
C++定义动态数组
给定一个二维数组a[6][6],分别定义函数求出该数组最大元素和其下标,最小元素和其下标,每行元素之和以及主