1. 函数参数的本质与使用场景
在C语言中,函数参数是函数与外界交互的重要通道。理解参数传递机制对于编写高效、可靠的代码至关重要。我们来看一个典型场景:当我们需要判断100-200之间的素数时,函数参数的设计直接影响代码的可读性和复用性。
1.1 值传递与地址传递的底层差异
C语言默认采用值传递方式,这意味着函数内部得到的是实参的副本。例如在素数判断函数中:
c复制int isPrime(int num) {
if(num <= 1) return 0;
for(int i=2; i*i<=num; i++) {
if(num % i == 0) return 0;
}
return 1;
}
这里的num参数会创建独立副本。当我们需要修改外部变量时,必须使用指针传递:
c复制void findPrimes(int start, int end, int results[], int *count) {
*count = 0;
for(int i=start; i<=end; i++) {
if(isPrime(i)) {
results[(*count)++] = i;
}
}
}
关键经验:数组名作为参数时实际传递的是数组首地址,本质上仍是指针传递。在32位系统中指针占4字节,64位系统占8字节,这与枚举类型大小(通常4字节)的认知常混淆。
1.2 main函数的参数解析
main函数的参数是理解命令行程序的关键:
c复制int main(int argc, char *argv[]) {
// argc: 参数个数
// argv: 参数数组
for(int i=0; i<argc; i++) {
printf("参数%d: %s\n", i, argv[i]);
}
return 0;
}
实际开发中常用atoi()将字符串参数转为数值,这在处理数值范围时特别有用。例如实现素数查找范围参数化:
bash复制./primeFinder 100 200
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 素数算法的优化实践
2.1 基础判断算法优化
最基础的素数判断需要遍历2到√n:
c复制int isPrimeBasic(int n) {
if(n <= 1) return 0;
for(int i=2; i*i<=n; i++) {
if(n%i == 0) return 0;
}
return 1;
}
优化点:
- 排除偶数(除2外)
- 只检查奇数因子
- 使用数学库sqrt()减少计算量
优化后版本:
c复制int isPrimeOptimized(int n) {
if(n <= 1) return 0;
if(n == 2) return 1;
if(n%2 == 0) return 0;
int limit = sqrt(n)+1;
for(int i=3; i<=limit; i+=2) {
if(n%i == 0) return 0;
}
return 1;
}
2.2 埃拉托斯特尼筛法实现
当需要批量查找素数时,筛法效率更高:
c复制void sieveOfEratosthenes(int start, int end) {
int *isPrime = (int*)malloc((end+1)*sizeof(int));
memset(isPrime, 1, (end+1)*sizeof(int));
isPrime[0] = isPrime[1] = 0;
for(int i=2; i*i<=end; i++) {
if(isPrime[i]) {
for(int j=i*i; j<=end; j+=i) {
isPrime[j] = 0;
}
}
}
for(int i=start; i<=end; i++) {
if(isPrime[i]) printf("%d ", i);
}
free(isPrime);
}
内存优化技巧:可以用位运算进一步压缩存储空间,每个素数只需1bit表示。
3. 100-200素数查找的完整实现
3.1 模块化设计实现
将功能分解为独立模块:
c复制// prime.h
#ifndef PRIME_H
#define PRIME_H
int isPrime(int num);
void findPrimesInRange(int start, int end, int printCount);
#endif
// prime.c
#include "prime.h"
#include <stdio.h>
#include <math.h>
int isPrime(int num) {
if(num <= 1) return 0;
if(num == 2) return 1;
if(num % 2 == 0) return 0;
for(int i=3; i*i<=num; i+=2) {
if(num % i == 0) return 0;
}
return 1;
}
void findPrimesInRange(int start, int end, int printCount) {
int count = 0;
for(int i=start; i<=end; i++) {
if(isPrime(i)) {
printf("%d%s", i, (++count % printCount == 0) ? "\n" : " ");
}
}
printf("\nFound %d primes between %d and %d\n", count, start, end);
}
// main.c
#include "prime.h"
int main() {
findPrimesInRange(100, 200, 10);
return 0;
}
3.2 性能对比测试
添加计时功能进行算法对比:
c复制#include <time.h>
void testPerformance() {
clock_t start, end;
double cpu_time_used;
start = clock();
// 测试基础算法
for(int i=0; i<10000; i++) {
isPrimeBasic(199);
}
end = clock();
cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC;
printf("Basic algorithm time: %f sec\n", cpu_time_used);
start = clock();
// 测试优化算法
for(int i=0; i<10000; i++) {
isPrimeOptimized(199);
}
end = clock();
cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC;
printf("Optimized algorithm time: %f sec\n", cpu_time_used);
}
典型输出结果:
code复制Basic algorithm time: 0.034215 sec
Optimized algorithm time: 0.012547 sec
4. 常见问题与调试技巧
4.1 边界条件处理
素数判断中常见的边界问题:
- 负数输入
- 0和1的特殊情况
- 大数溢出(如使用i*i<=n条件时)
防御性编程示例:
c复制int safeIsPrime(int num) {
if(num < 0) {
fprintf(stderr, "Error: Negative input\n");
return -1;
}
if(num <= 1) return 0;
/* 其余判断逻辑 */
}
4.2 调试输出技巧
在复杂算法中添加调试输出:
c复制int debugIsPrime(int num) {
printf("Checking %d...\n", num);
if(num <= 1) {
printf("%d is not prime (<=1)\n", num);
return 0;
}
for(int i=2; i*i<=num; i++) {
printf("Testing divisor %d...\n", i);
if(num % i == 0) {
printf("Found divisor: %d\n", i);
return 0;
}
}
printf("%d is prime\n", num);
return 1;
}
4.3 单元测试框架
简单实现测试用例验证:
c复制void testIsPrime() {
struct TestCase {
int input;
int expected;
} cases[] = {
{-1, -1}, {0, 0}, {1, 0}, {2, 1},
{3, 1}, {4, 0}, {9, 0}, {13, 1},
{100, 0}, {101, 1}, {199, 1}
};
for(int i=0; i<sizeof(cases)/sizeof(cases[0]); i++) {
int result = safeIsPrime(cases[i].input);
printf("Test %d: input=%d, expect=%d, got=%d - %s\n",
i+1, cases[i].input, cases[i].expected, result,
result == cases[i].expected ? "PASS" : "FAIL");
}
}
在VS Code中配置C语言环境时,合理使用调试断点和变量监视窗口可以显著提高调试效率。对于素数判断这类算法,特别适合在循环处设置条件断点观察变量变化。
