
本文共 4716 字,大约阅读时间需要 15 分钟。
3.1 数组
本章主要是介绍数组和字符串,两个都可以用来保存大量的数据。其中字符串可以视作一种特殊的字符数组,并且由于其特殊性,会介绍一些比较实用的方法和工具
数组的定义
“数组是指有序的元素序列。如果将有限个类型相同的变量的集合命名,那么这个名称就是数组名,而组成数组的各个变量称为数组的分量,也称为数组的元素,有时也称为下标变量。”
上面这段话引自 (标记出来的是我觉得比较重要的要点)
通常,我们在c++中用这样的方式定义一个一维数组(通常!毕竟我比较fw)
#inlcude<stdio.h>int main(){ 数组里面的变量类型名+空格+[最多能够存储多少个该类型] java中[]内可以不加数字表示没有固定数组的长度 但gcc的编译器这么做会报错 但可以像下面这样定义: char a[]="dhiuaslhf 32`14324"; int b[]={ 1,2,3,4,5,6,7}}
这里我举一个例子:
#include<stdio.h>int main(){ int a[10];}
这里我定义了一个可以放10个int型变量的a数组。
我们可以通过以下的方式给我们的数组赋值:
#include<stdio.h>int main(){ int a[10]={ 1,2,3,4,5,6,7,8,9,10};}
这个数组最多只能放10个int型的整数,如果放多了呢?
就会报出这样的错误
如果说我们只给数组的部分元素进行了赋值,那其他的元素的值会是多少呢?
其他几个元素的值是随机的(大概?反正不全是0就对了)
这里要注意的是对于a数组而言,第一个元素的下标是从0开始的,也就是说int a[10] 里面,包含的元素是a[0 - 9](懒得打字了,懂我意思就好2333
并且数组定义的大小是有范围的,因为调用的空间有限,有兴趣的可以尝试一下最大能定义到多少 (电脑:不,你没有兴趣
书上提到了一段代码
a[n++]=x;
事实上就是这两个代码合并起来
a[n]=x;n++;
至于优先级的问题,我搜了一下,++的优先度确实是比赋值要高的,所以也并不是很明白权当记忆了 (我是fw,如果有明白原理的麻烦告知以下)
memcpy 函数
使用这个函数首先是要包含头文件<string.h>的
格式是这样的:memcpy(存储目标内容的目标数组名,要复制的数据源,需要被复制的变量个数n)
注意到我这里没有加sizeof,事实上如果不加sizeof,这里默认的是两个字符串,如果需要进行更改,第三个参数位置这么写即可:sizeof(变量类型)*n (元素个数)。全部复制的话直接:sizeof(复制的数据源的数组名即可)
那如果要选择从哪里开始复制呢(不更改的话默认从头开始复制),需要更改第二个参数:要复制的数据源+开始复制的数组下标即可
选择从哪里存储被复制的元素的操作类似,更改第一个参数:存储目标内容的目标数组名+开始的下标
字符串(字符数组)的例子参考:
例子:
数组运用
还记得2.5排列的那道题目么,我们当时没有用数组的方法做,代码看起来非常的复杂,这里我们用数组重新再做一遍。
解决方案如下: (似乎也没有简单多少)
#include<stdio.h>#include<string.h>//用于调用memset int main(){ int a[10];//这个数组分别用来存储1-9中每个数字出现的次数,例如a[3]里面放的就是3出现了几次 for (int i=100;i<=333;i++){ memset(a,0,sizeof(a));//将数组a中所有元素全部赋值为0 //每次都要重新赋值一遍,防止对后面的循环造成影响 a[i%10]++;//i的个位十位百位 a[i%100/10]++; a[i/100]++; a[(2*i)%10]++;//2i的个位十位百位 a[(2*i)%100/10]++; a[(2*i)/100]++; a[(3*i)%10]++;//3i的个位十位百位 a[(3*i)%100/10]++; a[(3*i)/100]++; //现在a[1-9]分别放了其下标在这三个三位数中出现的次数 bool flag=true;//用于判断这个三位数是否符合条件 for (int j=1;j<=9;j++){ if (a[j]!=1)//如果1-9中的某个数不是出现一起且仅出现一次 { flag=false;//直接跳出循环 break; } } if (flag)//如果经历上面的循环,flag还没有变为false printf("%d %d %d\n",i,i*2,i*3); } return 0;}
这里运用了桶排序的思想
memset(a,0,sizeof(a))的作用是将a数组清零,它在string.h中定义。比起用for循环更加的快捷和方便
memset赋值赋值0就好了,不要想着把0的参数改了,去赋值其他的数字,事实上memset本身也是运用于字符串的工具,里面很多的用法和我们想的不是一样的,有兴趣的可以参考: 和
开灯问题
有 n 盏灯,编号为 1~n,第 1 个人把所有灯打开,第 2 个人按下所有编号为 2 的倍数的开关(这些灯将被关掉),第 3 个人按下所有编号为 3 的倍数的开关(其中关掉的灯将被打开,开着的灯将被关闭),依此类推。一共有 k 个人,问最后有哪些灯开着?输入:n 和 k,输出开着的灯编号。k≤n≤1000
样例输入: 7 3
样例输出: 1 5 6 7
分析:我们可以将这n盏灯看作数组里的n个元素,开始的时候都是关着的,我们可以将关着的这个状态定义为0 (bool 里面的 false),那么开灯就变为1。在模拟完整个过程后,遍历一遍下标为1-n的所有元素,元素值为1即为开着的灯,进行输出。
代码如下:
#include<stdio.h>#include<string.h>//用于调用memset int main(){ int a[1011],n,k; memset(a,0,sizeof(a)); scanf("%d%d",&n,&k); for (int i=1;i<=k;i++){ //一共k个人,进行k轮 for (int j=i;j<=n;j+=i) //这样做的原因可以减少循环和判断的次数,直接找到1-n中被i整除的数 a[j]=1-a[j];//0-->1,1-->0; } for (int i=1;i<=n;i++) if (a[i]) printf("%d ",i);//输出下标,即为处于开灯状态(1)的灯 return 0;}
书本上first的定义是用于规范格式的,因为有的oj对输出格式要求非常高,由于我没交oj,所以没有做这方面的处理
蛇形填数
给定一个 n , 在 n * n 的方阵中填入 1 ,2, 3,……,n * n, 要求填成蛇形。
例如在 n = 5 时 , 如下所示:
13 14 15 16 1
12 23 24 17 2
11 22 25 18 3
10 21 20 19 4
9 8 7 6 5
(markdown编辑器用的不是很熟T_T)
分析:我拿到这道题的时候乍一看想用dfs做,分析了一下,发现它填数的顺序还是比较有规律的。我们这里考虑使用二维数组,首先定义左上角为1,然后先往下,再往左,再往上,再往右进行填数。那么怎么判断什么时候开始转弯呢,在这个方阵的周围围上一圈障碍物即可。
首先什么叫做二维数组呢?
二维数组本质上是以数组作为数组元素的数组,即“数组的数组”。
这样子是不是感觉非常复杂?说的更加通俗一点。就是本来的一维数组里面的每一个元素,我们定义为一个数组。二维数组中就含有多个的一维数组。
事实上,二维数组通常以矩阵和方阵的形式表现出来,a[m][n],其中m即为行,n为列。(关系型数据库)
代码如下:
#include<stdio.h>#include<string.h>int a[30][30];//定义在main函数外的我们称为全局变量,全局变量是可以被本程序所有对象或函数引用int main(){ int n,x,y,tot=0; scanf("%d",&n); //x,y 为进行填数的格子的坐标 memset(a,0,sizeof(a));//将数组所有的元素赋值为0,为0的元素即为可以进行赋值(填数)的元素 for (int i=0;i<=n+1;i++){ //设置障碍 a[i][0]=1; a[i][n+1]=1; a[0][i]=1; a[n+1][i+1]=1; }}
代码写到这里,我们先输出来看一下:
n* n的方阵中,0的位置都是可以进行填数,那为什么我输出了n+1* n+1呢?事实上周围外面的一圈即做“障碍物”的作用,保证在填数的过程中不会,不会填到n*n的范围之外。
(我写完代码之后在这里想了一下,感觉似乎这圈“障碍物”不是完全必要的,但是为了保险起见,我还是预定义了一下。毕竟我是fw本废,T0T)
代码如下:
#include<stdio.h>#include<string.h>int a[30][30];//定义在main函数外的我们称为全局变量,全局变量是可以被本程序所有对象或函数引用int main(){ int n,x,y,tot=0; scanf("%d",&n); //x,y 为进行填数的格子的坐标 memset(a,0,sizeof(a));//将数组所有的元素赋值为0,为0的元素即为可以进行赋值(填数)的元素 for (int i=0;i<=n+1;i++){ //设置障碍 a[i][0]=1; a[i][n+1]=1; a[0][i]=1; a[n+1][i+1]=1; } x=1; y=n;//预定左上角的位置为开始填数的位置 a[x][y]=1; tot=1; while (tot<n*n){ //填n*n个数 while (a[x+1][y]==0){ //向下为可填的数则向下走 tot++; a[x+1][y]=tot; x++; } while (a[x][y-1]==0){ //向左为可填的数向左走 tot++; a[x][y-1]=tot; y--; } while (a[x-1][y]==0){ //向上为可填的数向上走 tot++; a[x-1][y]=tot; x--; } while (a[x][y+1]==0){ //向右为可填的数向右走 tot++; a[x][y+1]=tot; y++; } //一圈做完进行下一轮,直到数被全部填完 } for (int i=1;i<=n;i++){ for (int j=1;j<=n;j++) printf("%6d",a[i][j]); printf("\n"); }}
书上的代码非常的简洁,因为他将很多++还有赋值的代码放到了一起,还使用了! 的定义。但是正如书上所说,利用C语言简洁的语法的前提是,代码的准确性,和可读性。所以还是建议按照自己的习惯来嘛。
发表评论
最新留言
关于作者
