运算符优先级和数组定义

运算符优先级和数组定义

背景

按照筛法求素数的思想求出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
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
#include <stdio.h>
#include <math.h>
#define n 100

int main()
{ //const int n=100;

int a[n-1]={0}; //假设都是素数
for(int i=2;i<=sqrt(n);i++){
for(int j=0;j<n-1;j++){
if((j+2)%i==0&&j+2!=i){
a[j]=1;
}
}
}

//打印
int count=0;
for(int k=2;k<=n;k++){
if(a[k-2]==0){
printf("%5d",k);
count++;
}
if(count%10==0){
printf("\n");
}
}

return 0;
}

写代码中遇到的问题

(一)数组的定义:

问:我想定义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 语言规定:变长数组不能在定义时使用 {...} 进行初始化。

注意: 如果你学过 C++,你会发现 const int n = 100; int a[n]; 是完全合法的。这是 C 和 C++ 的一个重大区别!在 C++ 里,const 被视为真正的编译期常量,但在 C 里不是。

2. 那是不是非要用 #define

并不是只有 #define 这一条路,你有两个选择来解决这个问题:

方法一:宏定义 #define(最常用,推荐)

这是 C 语言处理数组大小的标准做法。

1
2
3
4
5
6
#define N 100

int main() {
int a[N] = {0}; // 完美,编译器看到的是 int a[100] = {0};
return 0;
}

==注意==

不能使用define N 1e2

因为 1e2( (1*10^2) )是浮点类型,而数组的定义要是整数类型

方法二:枚举 enum(高级一点的技巧)

如果你讨厌 #define(因为它没有类型检查,而且是全局替换),你可以用 enum。枚举成员在 C 语言中被视为真正的“整型常量表达式”。

1
2
3
4
5
6
enum { N = 100 };

int main() {
int a[N] = {0}; // 也是合法的,因为 N 是真正的常量
return 0;
}

(二)运算优先级

1
if(j + 2 % i == 0 && j + 2 != i)

在 C 语言中,取余运算符 % 的优先级比加法 + 高。 结果:程序实际上算的是 j + (2 % i),而不是你想要的 (j + 2) % i修正:加上括号 (j + 2) % i == 0

(三)多打印了一个回车

程序运行结果:

1
2
3
4
5
6
7
8
9
 2    3    5    7   11   13   17   19   23   29



31 37 41 43 47 53 59 61 67 71



73 79 83 89 97

解决:只需要把判断换行的代码,挪到打印数字if 括号里面。 逻辑变成:只有刚刚打印了一个素数,且这个素数是第 10 个时,才换行。

1
2
3
4
5
6
7
8
9
if (a[k - 2] == 0) { // 如果是素数
printf("%5d", k);
count++;

// 【修改】把换行判断放进来
// 只有当 count 增加后(确实打印了数字),才检查是否要换行
if (count % 10 == 0) {
printf("\n");
}

我的收获:

当我看到这个题目的时候,我是不会写的

但是看了哈基米的提示后,我才意识到这个重要的方法——标记数组

以后遇到这种一串数字在变动的时候,优先考虑先标记,而不是先定义数组。

在最后得到最终结果后再统一打印。

这个思路是非常值得学习的!


运算符优先级和数组定义
http://example.com/2025/12/06/运算符优先级和数组定义/
作者
王柏森
发布于
2025年12月6日
许可协议