C++从入门到放弃保姆级教程 — 数组
先提出一个问题,我们要输入一个整数,应该先声明一个变量吧。
那如果我们要100呢?声明100次?写一百个?那不是很麻烦。
所以解决办法是数组,声明是数组呢,就是一堆相同类型的数。
这样声明:
int a[100];
int b[x] = {1,2,3,4,5,6,7,8,9,10};
//这两种都是可以的,区别在于,b手动地给每个值赋值,并且x可以不写,如果要写的话,不能小于{...}里数据的个数,如果x大于了10 那么第11个数就没有初值。
这样就声明了100个int类型的数据,a就是这堆数的第一个的位置。
比如我想找第50个数,那就是a[50]。(其实是错误示范)
就是等于 a + 50 。但是 a + 50还不能拿来操作,因为说了a是位置,那a + 50也是位置,所以要操作的话,需要这样写:
*(a + 50) 这样就是等于 a[50]
⚠️这里注意,a + x是说距离a x位置的数,或者说x是偏移量,那么第一个数距离a就是0。
为什么要这样说呢,因为数组是0序的,不同于我们从1开始计数。数组是从0开始的。
a[0], a[1] ,a[2] ,a[3] ,a[4].....a[n]
比如上面声明了100个int类型的数据
最多只能操作到a[99]。
所以第50个数的正确写法是 a[49] 或者说*(a + 49)
- ⚠️这里也是新手很容易犯的错误,因为我们习惯上是1序。
- ⚠️用 [ ] 中括号更加安全,用*星号很危险
有人又要问了,那如果我操作a + 100,或者a - 1 会是什么样子呢
那么恭喜你,你遇到了你代码生涯中第一个错误。如果感兴趣读者可以自己下去尝试。常见的错误就是:
烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫
烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫
烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫
烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫
烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫
以"烫"为首的通篇的乱码 ,莫名其妙的数据,也可能什么事情都没有。
我们怎么对100个数进行操作呢?,还记得上一章讲的循环吗?我们可以用循环来对数组操作。
那么在这里提出一个问题:
告诉你一个数n,代表后面有n个数字会输入,你需要找出里面所有大于0的数,并且把排序输出。(n最大不超过10000,从小到大)
可以思考一下应该怎么操作
#include <iostream>
#include <algorithm>
using namespace std;
int main(){
const int N = 100010; //这里我们声明一个数字表示数组的最大值,因为上限有1w,所以要开1w多点,怕超出数组的范围,数组是不会变长的,声明时多长就只有多长。
//const 关键字的意思就是这个 N 是常量,不能修改,有些编译器里不加const 会报错
int a[N],b[N]; //a[N]表示最开始输入的数,b[N]表述我们筛选以后的,也就是不大于0的数
int n,m=0; //n是要输入的数字个数,m是给b[N]计数,也就是b数组里面有多少个数字
cin>>n;
for(int i = 0;i < n;i++)
cin>>a[i]; //输入数据到a[i]
for(int i = 0;i < n;i++){
if(a[i] <= 0)continue; //遇到continue关键字不会执行后面的内容,直接跳过一次循环,另外一个是break,直接结束循环。
b[m++] = a[i]; //把符合要求的a[i]数组赋值给b[m],同时m变成m+1;
}
sort(b, b + m); //有心的读者发现这次的头文件多了一个algorithm,这个是算法头文件,里面包含很多小工具,比如比较大小的max和min,排序的sort(默认升序)
//这里sort的意思是把b~b+m的数据进行排序。
for(int i = 0;i < m;i++){
cout << b[i] << endl;
}
//这里是输出
return 0;
}
如果有不明白的,就需要多看这段代码,如果还有不懂的可以留言。
二维数组
之前我们介绍的是一维的情况,现在来说2维的
int a[3][3];
//这里我声明了一个3*3的二维数组
如果当作一张表,给每个数赋值从左到右,从上倒下依次赋值结果是这样:
a [0] [1] [2]
[0] 1, 2, 3,
[1] 4, 5, 6,
[2] 7, 8, 9,
//怎么看呢,竖着的是高维,横着的是低维。
a[0][0] = 1 , a[0][1] = 2 , a[0][2] =3
a[1][0] = 4 , ...
... ...
为什么是这样呢?为什么呢为什么呢为什么呢?
还记得之前说的声明数组嘛?
如果我们把[3]当作一种数据类型
那么 int a[3][3]
是不是就是可以当作这样的:
int a[3][3];
a[0] --> {a[0][0], a[0][1], a[0][2]}
a[1] --> {a[1][0], a[1][1], a[1][2]}
a[2] --> {a[2][0], a[2][1], a[2][2]}
a[0], a[1], a[2] 我们总是舒熟悉的吧。
上面这些就是a[i]👆数组里的每个元素,然后每个元素又是数组
A [j]
(a[i]) [j]
二维数组好比,把这些集合当作另集合一个集合的元素
应该能理解了吧?
顺便来个思考题:
- 按照上面说的给一个100*100 的二维数组赋值,并打印出来。从左到右,从上往下。
- 写出9*9乘法表,没有的地方就直接空着:
1 x 1 = 1
2 x 1 = 2 2 x 2 = 4
3 x 1 = 3 3 x 2 = 6 3 x 3 = 9
… … … …
代码我就不写了,因为也不难,只要多思考就可以写出来
我才不会说是懒得写
提示需要用到双重for循环
for(int i = 0;i < n; i++){
for(int j = 0; j < m; j++){
......
}
}
字符串
前面提到过字符串对吧,当时我们是用的string 来表示的
但是真正的字符串应该是char s[100]。
用一个字符数组来表示字符串
#include <iostream>
#include <cstdio>
#define N 10000
using namespace std;
char s[N];
int main(){
scanf("%s",s);
int L = (int)strlen(s);
for(int i=0;i<L;i++)
cout << s[i];
cout<<endl;
return 0;
}
上面多加了点东西,一个是cstdio头文件包含了scanf函数,scanf()说起来又有些复杂,这里读者只需要知道,是读一个字符串就行了。
#define a b
是宏定义,就是全局替换,在cpp文件编译之前,就会把全文里所有的a换成b。
那么有什么用呢,比如可以自己写个max的宏
#define max(a, b) a > b? a : b //当然这种写法有问题,不过在这里我不会解释
...
c = max(a, b); == c = a > b? a : b;
#define max(a, b) (a) > (b)? (a) : (b) //这里的宏定义也不能避免所有的问题,
//但是这样写已经可以应付绝大多数问题了
如果你已经看到这里了,那么恭喜你,你已经学了相当一部分的知识了。但是看完 != 学会,还需要自己多做题,多思考,如果想进一步提升代码水准,推荐去 洛谷 做做一些入门题。
另外多说几个可以大幅提升水准的地方,
Peking Online Judge
Code Forces
还有什么hdu,voj很多很多。但是刚刚入门的人去,绝对是看不懂的。所以先做做洛谷的题吧。