数组(一)

本文深入探讨了C语言中数组的基本概念、声明、初始化、访问、操作以及高级特性,包括数组名、指针、二维数组、变长数组、复合文字等内容。详细解释了数组在C语言中的使用技巧及注意事项,旨在帮助读者更好地理解和掌握C语言数组的运用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基础

        1,数组在声明后就会被分配一个连续的地址空间,数组名代表的是当前的连续地址空间的首地址,也是该数组首元素的地址。例如a是一个数组,那么a==&a[0]是正确的。*(a+n)==a[n],a+n == &a[n]。ar[i]与*(a+i)是等同的,不管a是数组名还是一个指针变量。但只有当a是指针时,才能使用a++。

        2,如果数组声明时使用了const关键字,那么数组中的每个元素都是常量,只能在声明数组的时候进行初始化,因为声明之后不能再对数组进行赋值。

        3,数组名是该数组首元素的地址,因此数组名等同于一个指针处理数组的函数实际上是使用指针做为参数的,在编写处理数组的函数时,数组符号和指针符号都是可以选用的。

        4,如果不初始化数组,数组中存储的是无用的数值;如果部分初始化数组,未初始化的元素则被设置为0。在定义局部数组变量时,未初始化的元素不一定是0。为了保证其中所有元素的值都是0,可以写成int b[5]={0}.使用{}初始化数组时,可以省略数组的元素个数,例如上例中可以写成int a = {0},此时系统会根据{}中的数值数目来确定数组的大小。

        5,如果a是一个数组,可以把a[0]看作一个变量。

        6,二维数组在本质上也是一维数组,只不过它的元素是数组。存储时仍旧是一个连续空间,并且按行排列。首个元素是a[0][0],第二个元素是a[0][1],以此类推,直接第一行排完后才排第二行。

        7,与java类似,为数组中的某个元素进行赋值时,只是把右值中存储的值赋值给该元素或者直接把右值赋值给该元素(当右值不是变量名时)。如char *a[3];char *s="java_c_android";。使用a[1]=s时,直接把s中存储的地址赋值给a[1],也就是说a[1]现在也指向了字符串"java_c_android"的首地址。

        8,指针,数组做为参数时,它本身并不是一个数组,只是一个指向实参的首元素的指针。如:

void test(int * b){
	printf("test---%d\n",sizeof(b));
}
int main(void) {
	int a[5] ={0};
	printf("main---%d\n",sizeof(a));
	test(a);
}

        那么test方法中输出的是4(因为int类型占4个字节),而main中输出20(a有5个元素,每个元素占4个字节)。这是因为b只是一个指针,指向int数组a的首地址。总之a是一个数组,但test()中的b是一个指针,并不是一个数组(即使将b换成int b[]也是一样)。

        9,数组属于派生类型,因为它建立在其他的类型之上。其他类型本身就可以是一种数组类型,在这种情况下,得到的数组就是二维数组。

        10,使用数组名做为实际参数时,并不是将整个数组传递给函数,只是传递它的地址,因此相应的形参应该是一个指针。并且,处理数组时,还需要知道数组的长度——通常是用传递另一个参数专门用于标识数组的长度。

计算长度

        假设数组名为a,计算长度方法为sizeof(a)/sizeof(a[0]);

        sizeof(a)获取的是整个数组的字节数,而sizeof(a[0])获取的是一个元素的字节数。该方法获取的数组长度中,包含那些未被初始化的元素。

初始化指定元素

        c99中增加的新特性:允许选择对某些元素进行初始化。例如如果要对数组的最后一个元素进行初始化,传统写法为int a[] = {0,0,0,0,99};,而c99中可以写成int a[] = {[4]=99};,其含义如前面是一样的。

        这种初始化方式有两点:1,如果指定初始化元素后跟不止一个值,这些值是用来对指定元素后面的元素进行初始化的。例如int a[]={[1]=1,3,4}那么3,4就是用来初始化[2],[3]的。:2,如果一个元素有多个初始化的值,那么以最后一个为准

数组名

        在一般情况下,数组名代表的是数组首元素的地址。只有在两种情况下,数组名代表的是整个数组:

        (1),sizeof(数组名),返回的是整个数组所占的字节数,并不是首个元素所占的字节数。

        (2),对数组名取地址时。虽然输出时a(数组名)与&a的值一样,在内存中的位置也一样,但两者表示的含义完全不同:数组名代表数组中第一个元素的地址,数组名取地址则代表整个数组的地址。而且对两者执行+1操作后输出的结果也不一样:对a+1,指向数组中第二个元素,即a[1];对&a+1,则值移动sizeof(a)个位置,并不是指向a[1]元素。http://www.2cto.com/kf/201405/300332.html。因此,如果想将数组反向输出,可以如下:

    int a[] ={1,2,3,4,5,6,7},x=0,y=0;
    int (*p)[7] = &a;//指向数组的指针,即数组指针。
    /*
     * p+1:此时p指向数组中最后一个元素的下一位。
     * 将其强转成int *,为了使q-1时只移动一个int的字节,
     * 而不是移动a数组所占的字节数
     */
    int * q = (int *)(p+1);
    q--;//此时q指向数组中最后一个元素
    for(x=0;x<7;x++){
        printf("%d\n",*(q-x));
    }

        除了上述两种情况下,数组名一律退化为"指向数组首元素的指针"。但要注意:数组名仅仅是相当于指针,并不等同于指针。数组名是一个常量 ,它的值是数组首元素的地址,所以对数组名是无法进行++,--等操作的。

二维数组

        二维数组int a[m][n],其对应的是int ** pa。有如下关系:

*(*(a+m)+n)=a[m][n]

因为a指向的是由n个int数据组成的数组,所以a+m就将指针移动到了a[m];而a[m]是由int数据组成的数组的首地址,所以a[m]+n指向的是&a[m][n]。

        其形参声明方式为:int (*pa)[n]或者int pa[][n]。因为[]的运算优先级高于*,所以必须使用()将*pa括起来,表明pa是一个指针,其指向的类型为int [n]。

        一般地,声明N维数组的指针时,除了最左边的方括号中可以省略数字外,其他的都需要填写数值。这是因为首方括号表示这是一个指针,而其余的方括号用来描述所指向的对象的数据类型。而且ar[]可用(*ar)代替。如:

int (*ar)[1][2][3] == int ar[][1][2][3]

变长数组

        c99中,允许使用变量定义数组的维数,这个变并不意味着在创建数组后可以再改变其维数。由于数组的维数由变量控制,所以在定义数组之前必须先声明变量。如:

void test(int a[rows][cols],int rows,int cols);//不允许
void test(int rows,int cols,int a[rows][cols])//允许
        不允许按上面形式进行声明,因为rows,cols并没有提前声明。在函数声明时,通常不写形参名,那么变长数组的方括号内必须使用*代替数值。如下:
void test(int,int,int a[*][*]);

        变长数组必须在函数内部或作为形式参数,而且声明时不能进行初始化。如:

	int rows = 3,cols =2;
	int a[3][2] = {{1,2},{3,4},{5,6}};//允许,因为a不是变长数组
	int a[rows][cols] = {{1,2},{3,4},{5,6}};//不允许,变长数组不允许在声明时初始化

复合文字

        c99新加。

        5是int类型的文字,90.1是double类型的文字,"hellow"是字符串文字,而复合文字就是用来表示数组和结构内容的文字。

        表示方法为:(int[][2]){{1,2},{3,4},{5,6}},(int[]){1,3,4,5},即省略变量名并在前面用圆括号将类型括起来。该复合文字被标识为一个数组,并且这个常量代表着首元素的地址。因此以下代码是正确的:

int* p;
p = (int[]){1,2,3,4};
        复合文字通常用于给函数传递信息而不必先创建数组。

第1章 C语言概述 1 1.5 参照本章例题,编写一个C程序,输出以下信息: 1 1.6 写一个程序,输入a,b,c三个值,输出其中最大者。 1 第2章 程序的灵魂——算法 2 2.1 什么叫结构化的算法?为什么要提倡结构化的算法? 2 2.7 什么叫结构化程序设计?它的主要内容是什么? 2 第3章 数据类型、运算符与表达式 2 3.3请将下面各数用八进制和十六进制数表示: 2 3.4将以下三各整数分别赋给不同类型的变量,请画出赋值后数据在内存中的存储形式。 2 3.5字符常量和字符串常量有什么区别? 3 3.6写出以下程序运行的结果: 3 3.7要将“China”译成密码,密码规律是:用原来的字母后面第4个字母代替原来的字母。例如,字母“A”后面第4个字母是“E”,用“E”代替“A”。因此,“China”应译为“Glmre”。请编程序,用赋初值的方法使c1,c2,c3,c4,c5这5个变量的值分别为’C’,’h’,’i’,’n’,’a’,经过运算,使c1,c2,c3,c4,c5的值分别变为’G’,’l’,’m’,’r’,’e’,并输出。 4 3.8例2.6能否改成如下: 4 3.9求下面算术表达式的值。 4 3.10写出程序运行的结果。 5 3.11写出下面赋值的结果。格中写了数值的是要将它赋给其他类型的变量,将所有空格填上赋值后的数值。 5 3.12 出下面表达式运算后a的值,设原来a=12。设a和n都已定义为整型变量。 5 第4章 最简单的C程序设计——顺序程序设计 6 4.4 若a=3,b=4,c=5,x=1.2,y=2.4,z=-3.6,u=51247,n=128765,c1=’a’,c2=’b’,想得到以下的输出格式和结果,请写出程序(包括定义变量类型和设计输出)。 6 4.5请写出下面程序的输出结果: 7 4.6 用下面的scanf函数输入数据,使a=3,b=7,x=8.5,y=71.82,c1=’A’,c2=’a’。问在键盘上如何输入? 7 4.7下面的scanf函数输入数据,使a=10,b=20,c1=’A’,c2=’a’,x=1.5,y=-3.75,z=67.8,请问在键盘上如何输入数据? 8 4.8圆半径r=1.5,圆柱高h=3,求圆周长,圆面积,圆球表面积,圆球体积,圆柱体积。用scanf输入数据,输出计算结果,输出时要求有文字说明,取小数点后2位数字。请编程序。 8 4.9输入一个华氏温度,要求输出摄氏温度,公式为C=(5/9)(F-32) 9 输出要有文字说明,取2位小数。 9 第5章 选择结构程序设计 10 5.2语言中如何表示“真”和“假”?系统如何判断一个量的“真”和“假”? 10 5.3写出下面各逻辑表达式的值。设a=3,b=4,c=5。 10 5.4有3个整数a,b,c,由键盘输入,输出其中最大的数。 10 5.5有函数: 11 5.6给出百分制成绩,要求输出成绩等级’A’、’B’、’C’、’D’、’E’。90分以上为’A’,80~89分为’B’,70~79分为’C’,60~69分为’D’,60分以下为’E’。 12 5.7给定一个不多于5位的正整数,要求:①求它是几位数;②分别打印出每位数字;③按逆序打印出各位数字。例如原数为321,应输出123。 13 5.8企业发放的奖金根据利润提成。利润I低于或等于10万元时,奖金可提10%;利润高于10万元,低于20万元(100000<I≤200000)时,其中10万元按10%提成,高于10万元的部分,可提成7.5%;200000 <I≤400000时,其中20万元仍按上述办法提成(下同),高于20万元的部分按5%提成;400000<I≤600000时,高于40万元的部分按3%提成;6000001000000时,超过100万的部分按1%提成。从键盘输入当月利润I,求应发放奖金总数。 14 5.9输入4个整数,要求按由小到大的顺序输出。 16 5.10有4个圆塔,圆心分别为(2,2),(-2,2),(2,-2),(-2,-2),圆半径为1。见图4.4。这4个塔的高度分别为10m。塔以外无建筑物。今输入任点的坐标,求该点的建筑高度(塔外的高度为0)。 16 第6章 循环控制 17 6.1输入两个正整数m和n,求其最大公约数和最小公倍数。 17 6.2输入行字符,分别统计出其中英文字母,空格,数字和其它字符的个数。 18 6.3 18 6.4求∑n!(即求1+2!+…+20!)。 19 6.5求 19 6.6打印出所有的“水仙花数”。 20 6.7一个数如果恰好等于它的因子之和,这个数就称为“完数“。例如,6的因子为1,2,3,而6=1+2+3,因此6是“完数”。编程序找出1000以内的所有“完数”,并按下面的格式输出其因子:6 Its factors are 1,2,3 20 6.8有分数序列: 23 6.9球从100米高度自由落下,每次落地后反跳回原高度的半,再落下。求它在第10次落地时,共经过多少m?第10次反弹多高? 23 6.10猴子吃桃问题。猴子第天摘下若干个桃子,当即吃了半,还不过瘾,又多吃了一个。第二天早上又将剩下的桃子吃掉半,又多吃了一个。以后每天早上都吃了前天剩下的半零一个。到第10天早上再想吃时,见只剩一个桃子了。求第天共摘多少桃子。 24 6.11用迭代法求 24 6.12用牛顿迭代法求方程2x3-4x2+3x-6=0在1.5附近的根。 25 6.13用二分法求方程2x3-4x2+3x-6=0在(-10,10)之间的根。 26 6.14打印出以下图案: 27 6.15两个乒乓球队进行比赛,各出3人。甲队为A、B、C3人,乙队为X、Y、Z3人。已抽签决定比赛名单。有人向队员打听比赛名单。A说他不和X比,C说他不和X、Z比。请编程找出3对赛手的名单。 28 第7章 数组 28 7.1用筛法求100之内的素数。 28 7.2用选择法对10个整数排序(从小到大)。 30 7.3求一个3×3矩阵对角线元素之和。 31 7.4有一个已排好序的数组,今输入一个数,要求按原来排序的规律将它插入数组中。 32 7.5将一个数组中的值按逆序重新存放。例如原来顺序为:8,6,5,4,1。要求改为:1,4,5,6,8。 34 7.6打印出以下的杨辉三角形(要求打印出10行)。 35 7.7输出魔方阵。所谓魔方阵是指这样的方阵(方阵的阶数应为奇数),它的每行、每列和对角线之和均相等。 36 7.8找出一个二维数组中的鞍点,即该位置上的元素在该行上最大,在该列上最小。也可能没有鞍点。 38 7.9有15个数按从小到大的顺序存放在一个数组中。输入一个数,要求用折半查找法找出该数是数组中第几个元素的值。如果该数不在数组中,输出“不在表中”。 39 7.10有篇文章,共有3行文字,每行有80个字符。要求分别统计出其中英文大写字母,小写字母,数字,空格以及其它字符的个数。 41 7.11打印以下图案: 42 7.12有行电文,已按下面规律译成密码: 43 7.13编一个程序,将两个字符串连接起来,不要用strcat函数。 45 7.14编一个程序,将两个字符串s1和s2进行比较。如果s1>s2,输出一个正数;s1=s2,输出0;s1<s2,输出一个负数。不要用strcmp函数。两个字符串用gets函数读入。输出的正数或负数的绝对值应是相比较的两个字符串相应字符的ASCII码的差值。例如,’A’与’C’相比,由于’A’<’C’,应输出负数,由于’A’与’C’的ASCII码的差值为2,因此,应输出”-2”。同理:’’And’’和”Aid”比较,根据第2个字符比较结果,’n’比’i’大5,因此应输出’5’。 45 7.15编写一个程序,将字符数组s2的全部字符拷贝到字符数组s1中,不用strcpy函数。拷贝时,’\0’也要拷过去,’\0’后面的字符不拷贝。 46 第8章 函数 47 8.1写两个函数,分别求两个整数的最大公约数和最小公倍数,用主函数调用这两个函数,并输出结果,两个整数由键盘输入。 47 8.2 47 8.3写一个判素数的函数,在主函数输入一个整数,输出是否素数的信息。 49 8.4写函数,使给定的一个二维数组(3×3)转置,即行列互换。 49 8.5写函数,使输入的一个字符串按反序存放,在主函数中输入和输出字符串。 50 8.6写函数,将两个字符串连接。 51 8.7写函数,输入一个4位数字,要求输出这4个数字字符,但每两个数字之间有一个空格。如输入1990,应输出”1 9 9 0”。 52 8.8编写函数,有实参传来一个字符串,统计此字符串中字母,数字,空格和其它字符的个数,在主函数中输入字符串以及输出上述的结果。 52 8.10写函数,用“起泡法”对输入的10个字符按由小到大的顺序排列。 54 8.11用弦截法求根。 55 8.12输入10个学生5门课的成绩,分别用函数求:(1)每个学生的平均分;(2)每门课的平均分;(3)找出最高的分数所对应的学生和课程;(4)求出平均分方差; 57 8.13写几个函数:(1)输入10个职工的姓名和职工号;(2)按职工号由小到大排序,姓名顺序也随之调整;(3)要求输入一个职工号,用折半查找法找出该职工的姓名。 61 8.14写函数,输入一个十六进制数,输出相应的十进制数。 64 8.15给出年,月,日,计算该日是该年的第几天。 65 第9章 预处理命令 66 9.1定义一个代参数的宏,使两个参数的值互换,并写出程序,输入两个数作为使用宏时的实参。输出已交换后的两个值。 66 9.2输入两个整数,求它们相除的余数。用带参的宏来实现,编程序。 67 9.3 67 9.4给年份year定义一个宏,以判断该年份是否为闰年。 68 9.5请分析以下组宏所定义的输出格式: 68 9.6请设计输出实数的格式。实数用“6.2f”格式输出。 69 9.7分别用函数和带参的宏,从3个数中找出最大数。 70 9.8试述“文件包含”和程序文件的连接(link)的概念,二者有何不同? 71 9.9用条件编译法实现以下功能: 71 第10章 指针 72 10.1输入3个整数,按由小到大的顺序输出。 72 10.2输入3个字符串,按由小到打的顺序输出。 73 10.3输入10个整数,将其中最小的数与第一个数对换,把最大的一个数与最后一个对换。写3个函数:(1)输入10个数;(2)进行处理;(3)输出10个数。 74 10.4有n个整数,使其前面各数顺序向后移m个位置,最后m个数变成前面m个数。 75 写函数实现以上功能,在主函数中输入n个整数,并输出调整后的n个数。 75 10.5有字符串,包含n个字符。写一个函数,将此字符串中从第m个字符开始的全部字符复制成为另一个字符串。 76 10.6输入行文字,找出其中大写字母,小写字母,空格,数字及其他字符各有多少。 77 10.7写一个函数,将一个3×3的矩阵转置。 77 9.8将一个5×5的矩阵中最大的元素放在中心,4个角分别放在4个最小的元素(按从左到右,从上到下的顺序,依次从小到大存放),写一个函数实现之,并用main函数调用。 78 10.9在主函数中输入10个等长的字符串。用另一个函数对它们排序,然后在主函数输出这10个已排好序的字符串。 80 10.10用指针数组处理上题目,字符串不等长。 81 10.11将n个数按输入输出顺序的逆序排列,用函数实现。 82 10.12有一个班4个学生,5门课。(1)求第门课的平均分;(2)找出有两门以上课程不及格的学生,输出他们的学号和全部课程成绩及平均成绩;(3)找出平均成绩在90分以上或全部课程成绩在85分以上的学生。分别编3个函数实现上3个要求。 83 10.13输入一个字符串,内有数字和非数字字符,如: 86 10.14写函数,实现两个字符串的比较。即自己写一个strcmp函数,函数原型为: 88 10.15编写一个程序,打入月份号,输出该月的英文月名。例如,输入”3”,则输出”March”,要求用指针数组处理。 89 10.16用指向指针的指针的方法对5个字符串排序并输出。 89 10.17用指向指针的指针的方法对n个整数排序并输出。要求将排序单独写成一个函数。n和正整数在主函数中输入。最后在主函数中输出。 90 第11章 结构体与共用体 91 11.1定义一个结构体变量(包括年,月,日)。计算该日在本年中是第几天,注意闰年问题。 91 11.2写一个函数days,实现上面的计算。由主函数将年,月,日传递给days函数,计算后将日数传回主函数输出。 93 11.3编写一个函数print,打印一个学生的成绩数组,该数组中有5个学生的数据记录,每个记录包括num,name,score[3],用主函数输入这些记录,用print函数输出这些记录。 95 11.4在上题的基础上,编写一个函数input,用来输入5个学生的数据记录。 97 11.5有10个学生,每个学生的数据包括学号,姓名,3门课的成绩,从键盘输入10个学生的数据,要求打印出3门课的总平均成绩,以及最高分的学生的数据(包括学号,姓名,3门课成绩,平均分数)。 97 11.6编写一个函数new,对n个字符开辟连续的存储空间,此函数应返回一个指针(地址),指向字符串开始的空间。new(n)表示分配n个字节的内存空间。 100 11.7写函数free,将上题new函数占用的空间释放free(p)表示将p(地址)指向的单元以后的内存段释放。 101 11.8已有a,b两个链表,每个链表中的结点包括学号,成绩。要求把两个链表合并,按学号升序排列。 101 11.9有两个链表a和b,设结点中包含学号,姓名。从a链表中删去与b链表中有相同学号的那些结点。 104 11.10建立一个链表,每个结点包括:学号,姓名,性别,年龄。输入一个年龄,如果链表中的结点所包含的年龄等于此年龄,则将此结点删去。 106 第12章 位运算 109 12.1编写一个函数getbits,从一个16位的单元中取出某几位()即该几位保留原值,其余位为0)。函数调用形式为: 109 12.2写一个函数,对一个16位的二进制数取出它的奇位数(即从左边起第1,3,5,…,15位)。 109 12.3编程序,检查下你所用的计算机系统的C编译在执行右移时是按照逻辑位移的原则,还是按照算术右移的原则。如果是逻辑右移,请编函数实现算术右移;如果是算术右移,请编函数实现逻辑右移。 110 12.4编函数用来实现左右循环移位。函数名为move,调用方法为:move(value,n) 112 其中value为要循环位移的数,n为位移的位数。如n0为右移。如n=4,表示要右移4位;n=-3,表示要左移3位。 112 第13章 文件 113 13.3从键盘输入一个字符串,将其中的小写字母全部转换成大写字母,然后输出到一个磁盘文件”test”中保存。输入的字符串以”!”结束。 113 13.4有两个磁盘文件“A”和“B”,各存放行字母,要求把这两个文件中的信息合并(按字母的顺序排列),输出到一个新文件“C”中。 114 13.5有5个学生,每个学生有3门课的成绩,从键盘输入以上数据(包括学生号,姓名,三门课成绩),计算出平均成绩,将原有数据和计算出的平均分数存放在磁盘文件stud中。 115 13.7将上题已排序的学生成绩文件进行插入处理。插入一个学生的3门课成绩,程序先计算新插入学生的平均成绩,然后将它按平均成绩高低顺序插入,插入后建立一个新文件。 122 13.8将上题的结果仍存入原有的stu_sort文件而不另建立新文件。 123 13.9有磁盘文件emploee,内存放职工的数据。每个职工的数据包括:职工姓名,职工号,性别,年龄,住址,工资,健康状况,文化程度。要求将职工名和工资的信息单独抽出来另建一个简明的职工工资文件。 125 13.10从上题的“职工工资文件”中删去一个职工的数据,再存回原文件。 127
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值