运算符优先级和数组定义
运算符优先级和数组定义
背景
按照筛法求素数的思想求出100以内的所有素数。每行10个。
**输出格式要求:”%5d”
用筛法求素数的基本思想是:把从2到N的一组正整数从小到大按顺序排列。从中依次删除2的倍数、3的倍数、5的倍数,直到根号N的倍数为止,剩余的即为2~N之间的所有素数。如有:
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
去掉2的倍数(不包括2),余下的数是:
3 5 7 9 11 13 15 17 19 21 23 25 27 29
剩下的数中3最小,去掉3的倍数,如此下去直到sqrt(30)的倍数,
最后求出的素数为:
2 3 5 7 11 13 17 19 23 29
代码实现
1 | |
写代码中遇到的问题
(一)数组的定义:
问:我想定义int a[n-1]={0},这里的n我想设置为100,所以我在前面定义int n=100,为什么不行?提示我的n要为不可变常量,所以我定义const int n=100,为什么又不行,我的n明显是const常量啊,难道非要定义#define n 100吗?
答:
在 C 语言中,const int n = 100; 并不是真正的“常量”,而是一个“只读变量”。
是不是听起来像绕口令?别急,我来给你拆解一下这背后的逻辑。
1. 为什么 const 不行?(“只读变量” vs “常量”)
在 C 语言的标准(特别是 C89/C90 和 C99)中:
#define N 100: 这是一个预处理指令。在编译代码之前,编译器会先把代码里所有的N简单粗暴地替换成100。- 对编译器来说:
int a[N]等同于int a[100]。 - 编译器明确知道大小是 100,所以允许你用
{0}初始化。
- 对编译器来说:
const int n = 100: 这对 C 语言编译器来说,n依然是一个变量(Variable),只不过是一个“你承诺不去修改它的变量”(Read-only Variable)。- 虽然它的值是 100,但在严格的 C 语言规则里,它属于运行时(Runtime)的概念,而数组的大小和初始化(
{...})需要在编译时(Compile-time)确定。 - 当你写
int a[n]时,这就变成了一个变长数组(VLA)。 - C 语言规定:变长数组不能在定义时使用
{...}进行初始化。
- 虽然它的值是 100,但在严格的 C 语言规则里,它属于运行时(Runtime)的概念,而数组的大小和初始化(
注意: 如果你学过 C++,你会发现
const int n = 100; int a[n];是完全合法的。这是 C 和 C++ 的一个重大区别!在 C++ 里,const被视为真正的编译期常量,但在 C 里不是。
2. 那是不是非要用 #define?
并不是只有 #define 这一条路,你有两个选择来解决这个问题:
方法一:宏定义 #define(最常用,推荐)
这是 C 语言处理数组大小的标准做法。
1 | |
==注意==
不能使用define N 1e2
因为 1e2( (1*10^2) )是浮点类型,而数组的定义要是整数类型
方法二:枚举 enum(高级一点的技巧)
如果你讨厌 #define(因为它没有类型检查,而且是全局替换),你可以用 enum。枚举成员在 C 语言中被视为真正的“整型常量表达式”。
1 | |
(二)运算优先级
1 | |
在 C 语言中,取余运算符 % 的优先级比加法 + 高。 结果:程序实际上算的是 j + (2 % i),而不是你想要的 (j + 2) % i。 修正:加上括号 (j + 2) % i == 0
(三)多打印了一个回车
程序运行结果:
1 | |
解决:只需要把判断换行的代码,挪到打印数字的 if 括号里面。 逻辑变成:只有刚刚打印了一个素数,且这个素数是第 10 个时,才换行。
1 | |
我的收获:
当我看到这个题目的时候,我是不会写的
但是看了哈基米的提示后,我才意识到这个重要的方法——标记数组
以后遇到这种一串数字在变动的时候,优先考虑先标记,而不是先定义数组。
在最后得到最终结果后再统一打印。
这个思路是非常值得学习的!