3.1数组
数组和字符串都能保存大量的数据。字符串是一种数组(字符数组),但由于其应用的特殊性,适用一些特别的处理方式。
3-1逆序输出
读入一些数,逆序输出到一行中,已知整数不超过100个。其他办法读出来就没事可做了,没有一个存放的地方,那有什么办法吗?答案:数组。
//3-1 逆序输出 #include<stdio.h> #define maxn 105 int a[maxn]; int main() { int x,n=0; while(scanf("%d",&x) == 1) a[n++] = x; for(int i =n-1;i>=1;i--) printf("%d",a[i]); printf("%d\n",a[0]); return 0; }语句“int a[maxn]”声明了一个包含maxn个整形变量的数组,他们是:a[0],a[1],a[2],a[maxn-1].但是不包含a[maxn].maxn必须是常数不能是变量。maxn为105不为100,这样是为了更保险。
const 和 #define 的作用与区别
const是C/C++关键字,定义常量变量;#define是预处理宏,属于预处理器指令,不是C语言语句。
1. 作用
#define 宏定义
#define MAX 100预处理阶段做简单文本替换:代码里所有MAX原样替换成100,没有类型检查,不分配内存。
- 常用于定义字面量常量、宏函数、头文件保护。
const 修饰常量
const int max = 100;定义一个只读变量,有数据类型,编译期做类型检查,会分配内存(大部分情况),值不能被修改。
C语言:
const是只读变量,不是真正编译期常量,不能当数组大小;C++中const可以作为编译期常量。
2. 核心区别
| 对比项 | #define | const |
|---|---|---|
| 处理阶段 | 预处理阶段,文本替换 | 编译阶段,处理变量 |
| 数据类型 | 无类型,纯文本替换 | 有明确数据类型,编译器类型检查 |
| 内存分配 | 不分配内存,直接替换文本 | 分配内存,是只读变量 |
| 作用域 | 默认整个文件,#undef可以取消 | 遵循变量作用域(局部/全局) |
| 调试 | 没有符号,调试器看不到宏名 | 有变量符号,方便调试 |
| 指针坑 | 不会做类型校验,容易出错 | const指针可以限定读写权限 |
| 数组大小(C) | 可以int arr[MAX] | C语言不能int arr[max];C++可以 |
坑点示例:#define 的副作用
#define A 2+3 int b = A * 2; // 文本替换后:int b = 2+3*2; → 结果8,不是10! // 宏要加括号:#define A (2+3)const不会出现这个问题:
const int a = 2+3; int b = a * 2; // 正常得到103. 使用建议
- 优先用 const:有类型检查,作用域可控,便于调试,C++推荐。
#define适用场景:头文件保护#ifndef、简单宏函数、跨编译期字面量。- C语言如果需要编译期常量做数组长度,可以用
enum枚举。
补充C++小知识点
C++11之后推荐:constexpr,真正编译期常量,兼顾const类型安全和宏的编译期计算。
constexpr int num = 100;a[n++]=x做了两件事情,第一就是把x的值赋给a[n];第二件事就是n=n+1。 对于“++”有a++和++a两种,都会给a+1,但是有所差别:n++会使用+1前的值计算表达式;而++n则是使用加1后的值计算表达式。
比较大的数组尽量声明在main函数外,否则程序无法进行。
我自己测试了极限是10000000000000000000000000,但是发现在main的内外没区别。
局部变量(写在main或者普通函数内部)是放在栈 (stack)上;全局变量(写在main外面)放在静态存储区(全局区)。 栈空间很小,大数组放函数内会栈溢出;全局区空间大,适合放大数组。 不是 “程序无法进行” 这么绝对,而是大概率运行崩溃。
懂了,但是我没有证明成功。二者都是在10000000000000000000000000时报错太长。
数组在C语言中的地位是非常低下的
数组不能进行赋值操作,如果声明的是“int a[maxn],b[maxn]”,是不能赋值b = a的。如果要从数组a复制k个元素到数组b,可以这样做: memcpy(b,a,sizeof(int) * k).当然,如果数组a和b都是浮点型的,复制时要写出"memcpy(b,a,sizeo(double) * k).”另外需要注意的是,使用memcpy函数要包含头文件string.h。如果需要把数组a全部复制到数组b中,可以写得简单一些:memcpy(b,a,sizeof(a))。
开灯问题。有n盏灯,编号为1~n。第1个人把所有的灯打开,第二个人按下所有编号为2的倍数的开关(这些灯将被关掉),第3个人按下所有编号为3的倍数的开关(其中关掉的灯将被打开,开着的灯将被关闭),以此类推。一共有k个人,问最后有哪些灯还亮着?输入n和k,输出开着的灯的编号。k<=n<=1000。
样例输入:
7 3
样例输出:
1 5 6 7
#include<stdio.h> const int MAXN = 1001; int a[MAXN]; int main(){ int n,k; scanf("%d %d",&n,&k); for(int i=1;i<=k;i++)//这代表第几个人 { for(int s=i;s<=n;s+=i){//这代表 a[s]++; } } for(int q =1;q<=n;q++) { if(a[q]%2==1) printf("%d\n",q); } return 0; }从这个题目中我知道了数组在main内外的定义所带来的不同效果,以上是通过AI的协助所做的。我的代码如下:
#include<stdio.h> int main(){ int n,k; int a[1001]; scanf("%d %d",&n,&k); for(int i=1;i<=k;i++)//这代表第几个人 { for(int s=i;s<=n;s+=i){//这代表 a[s]++; } } for(int q =1;q<=n;q++) { if(a[q]%2==1) printf("%d\n",q); } return 0; }这个我经过检验发现输入7,3之后的结果:
1 5 而不是1 5 6 7。
#include <stdio.h> #include <string.h> #define maxn 1010 int a[maxn]; int main() { int n, k, first = 1; memset(a, 0, sizeof(a)); scanf("%d%d", &n, &k); for(int i = 1; i <= k; i++) for(int j = 1; j <= n; j++) if(j % i == 0) a[j] = !a[j]; for(int i = 1; i <= n; i++) if(a[i]) { if(first) first = 0; else printf(" "); printf("%d", i); } printf("\n"); return 0; }这个是课本上的答案比较巧妙,其中:
1.“memset(a,0,sizeof(a))"的作用是把数组a清零,它也在string.h中定义。虽然也能用fo循环完成相同的任务,但是用memset又方便又快捷。另一个技巧在输出:为了避免输出多余空格,设置了一个标志变量first,可以表示当前要输出的变量是否为第一个。第一个变量前面没有空格,但其他变量都有。
2.他这里判断”灯“是否是开着的用的不是奇偶,而是0,1是取反所以这很像开关了,也比较好判断。