C程序设计(第五版)谭浩强 第七章课后习题优化算法与核心步骤解析

1.写两个函数,分别求两个整数的最大公约数和最小公倍数,用主函数调用这两个函数,并输出结果。两个整数由键盘输入。

cpp 复制代码
#include <stdio.h>
// 函数声明
int gcd(int a, int b);     // 求最大公约数
int lcm(int a, int b);     // 求最小公倍数
int main() {
    int num1, num2;
     // 输入两个整数
    printf("请输入两个正整数:");
    scanf("%d %d", &num1, &num2);
    // 输入验证
    if(num1 <= 0 || num2 <= 0) {
        printf("错误:请输入正整数!\n");
        return 1;
    }
     // 调用函数并输出结果
    int gcd_result = gcd(num1, num2);
    int lcm_result = lcm(num1, num2);
    printf("\n计算结果:\n");
    printf("%d 和 %d 的最大公约数是:%d\n", num1, num2, gcd_result);
    printf("%d 和 %d 的最小公倍数是:%d\n", num1, num2, lcm_result); 
    // 验证公式:a * b = gcd(a,b) * lcm(a,b)
    printf("\n公式验证:\n");
    printf("%d × %d = %d\n", num1, num2, num1 * num2);
    printf("%d × %d = %d\n", gcd_result, lcm_result, gcd_result * lcm_result);  
    if(num1 * num2 == gcd_result * lcm_result) {
        printf("验证通过:两数乘积 = 最大公约数 × 最小公倍数\n");
    }   
    return 0;
}

// 函数定义:求最大公约数(辗转相除法/欧几里得算法)
int gcd(int a, int b) {
    int temp;    
    // 确保a >= b
    if(a < b) {
        temp = a;
        a = b;
        b = temp;
    }   
    // 辗转相除
    while(b != 0) {
        temp = a % b;  // 求余数
        a = b;         // 除数变被除数
        b = temp;      // 余数变除数
    }    
    return a;  // 循环结束时a就是最大公约数
}
// 函数定义:求最小公倍数
int lcm(int a, int b) {
    // 利用公式:最小公倍数 = 两数乘积 ÷ 最大公约数
    // 注意:先除后乘避免溢出
    return a / gcd(a, b) * b;
}

2.求方程的根,用3个函数分别求当:大于0、等于0和小于0时的根并输出结果。从主函数输人a, b, c的值。

cpp 复制代码
#include <stdio.h>
#include <math.h>
//处理大于0的情况
void big(double a, double b, double d) {
    double x1 = (-b + sqrt(d)) / (2 * a);
    double x2 = (-b - sqrt(d)) / (2 * a);
    printf("x1 = %.3lf  x2 = %.3lf\n", x1, x2);
}
//处理等于0的情况
void equal(double a, double b) {
    double x = -b / (2 * a);
    printf("x1 = x2 = %.3lf\n", x);
}
//处理小于0的情况
void small(double a, double b, double d) {
    double real = -b / (2 * a);
    double imag = sqrt(-d) / (2 * a);
    printf("x1 = %.3lf + %.3lfi  x2 = %.3lf - %.3lfi\n", real, imag, real, imag);
}

int main() {
    double a, b, c, delta;
    scanf("%lf%lf%lf", &a, &b, &c);
    delta = b * b - 4 * a * c;
    if (delta > 0) {
        big(a, b, delta);
    } else if (delta == 0) {
        equal(a, b);
    } else {
        small(a, b, delta);
    }
    return 0;
}

3.写一个判素数的函数,在主函数输人一个整数,输出是否为素数的信息。

cpp 复制代码
#include <stdio.h>
//判断素数的函数
int isprime(int a) {
    int i;
    //从2开始到a/2进行整除测试
    for(i = 2; i <= a / 2; i++) {
        //如果能被整除,说明不是素数
        if(a % i == 0) return 0;
    }
    //如果循环完整结束,说明是素数
    if(i > a / 2) return 1;
    return 0;  //这一行实际上不会执行,但为了编译完整性保留
}
 
int main() {
    int x, flag;
    printf("请输入一个整数:");
    scanf("%d", &x);
    //调用函数判断素数
    flag = isprime(x);
    //根据返回值输出结果
    if(flag == 1) printf("%d是素数\n", x);
    else printf("%d不是素数\n", x);
    return 0;
}

4.写一个函数,使给定的一个3×3的二维整型数组转置,即行列互换。

cpp 复制代码
#include <stdio.h>
//矩阵转置函数
void transpose(int matrix[3][3]) {
    int temp;
    //只遍历上三角矩阵,与对应的下三角元素交换
    for (int i = 0; i < 3; i++) {
        for (int j = i + 1; j < 3; j++) {
            //交换行列元素
            temp = matrix[i][j];
            matrix[i][j] = matrix[j][i];
            matrix[j][i] = temp;
        }
    }
}

//打印矩阵函数
void printMatrix(int matrix[3][3]) {
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            printf("%d ", matrix[i][j]);
        }
        printf("\n");
    }
}

int main() {
    int matrix[3][3];
    
    //输入3×3矩阵
    printf("请输入3×3矩阵的元素:\n");
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            scanf("%d", &matrix[i][j]);
        }
    }
    
    printf("原始矩阵:\n");
    printMatrix(matrix);
    
    //调用转置函数
    transpose(matrix);
    
    printf("转置后的矩阵:\n");
    printMatrix(matrix);
    
    return 0;
}

5.写一个函数,使输入的一个字符串按反序存放,在主函数中输入和输出字符串。

cpp 复制代码
#include <stdio.h>
#include <string.h>

//字符串反序存放函数
void reverseString(char str[]) {
    int length = strlen(str);
    char temp;
    //交换首尾对应字符
    for (int i = 0; i < length / 2; i++) {
        temp = str[i];
        str[i] = str[length - 1 - i];
        str[length - 1 - i] = temp;
    }
}

int main() {
    char str[100];
   printf("请输入一个字符串:");
    gets(str);
    reverseString(str);
    printf("反序后的字符串:%s\n", str); 
    return 0;
}

6.写一个函数,将两个字符串连接。

cpp 复制代码
#include <stdio.h>
//字符串连接函数
void concatStrings(char str1[], char str2[], char result[]) {
    int i = 0, j = 0;
    
    //复制第一个字符串到结果
    while (str1[i] != '\0') {
        result[i] = str1[i];
        i++;
    }
    
    //连接第二个字符串到结果
    while (str2[j] != '\0') {
        result[i] = str2[j];
        i++;
        j++;
    }
    
    //添加字符串结束符
    result[i] = '\0';
}

int main() {
    char str1[100], str2[100], result[200];  
    printf("请输入第一个字符串:");
    gets(str1);    
    printf("请输入第二个字符串:");
    gets(str2);    
    concatStrings(str1, str2, result);   
    printf("连接后的字符串:%s\n", result);  
    return 0;
}

7.写一个函数,将一个字符串中的元音字母复制到另一字符串,然后输出。

cpp 复制代码
#include <stdio.h>
#include <string.h>

//复制元音字母函数
void copyVowels(char source[], char vowels[]) {
    int i = 0, j = 0;
    
    while (source[i] != '\0') {
        char ch = source[i];
        //判断是否为元音字母(包括大小写)
        if (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u' ||
            ch == 'A' || ch == 'E' || ch == 'I' || ch == 'O' || ch == 'U') {
            vowels[j] = ch;
            j++;
        }
        i++;
    }
    vowels[j] = '\0';  //添加字符串结束符
}

int main() {
    char str[100], vowelStr[100];
    
    printf("请输入一个字符串:");
    gets(str);
    
    copyVowels(str, vowelStr);
    
    printf("元音字母:%s\n", vowelStr);
    printf("元音字母数量:%d\n", strlen(vowelStr));
    
    return 0;
}

8.写一个函数,输入一个4位数字,要求输出这4个数字字符,但每两个数字间空一个空格。如输入1990,应输出"1 9 9 0"。

cpp 复制代码
#include <stdio.h>
#include <string.h>

//格式化输出四位数函数
void formatNumber(char numStr[]) {
    int length = strlen(numStr);
    
    //确保输入的是4位数
    if (length != 4) {
        printf("请输入4位数字!\n");
        return;
    }
    
    //按格式输出:数字 空格 数字 空格 数字 空格 数字
    printf("格式化输出:");
    for (int i = 0; i < 4; i++) {
        printf("%c", numStr[i]);
        if (i < 3) {
            printf(" ");
        }
    }
    printf("\n");
}

int main() {
    char num[5];
    
    printf("请输入一个4位数字:");
    scanf("%s", num);
    
    formatNumber(num);
    
    return 0;
}

9.编写一个函数,由实参传来一个字符串,统计此字符串中字母、数字、空格和其他字符的个数,在主函数中输入字符串以及输出上述的结果。

cpp 复制代码
#include <stdio.h>
#include <ctype.h>

//统计字符类型函数
void countCharacters(char str[], int *letters, int *digits, int *spaces, int *others) {
    *letters = *digits = *spaces = *others = 0;
    
    for (int i = 0; str[i] != '\0'; i++) {
        if (isalpha(str[i])) {
            (*letters)++;           //字母
        } else if (isdigit(str[i])) {
            (*digits)++;            //数字
        } else if (isspace(str[i])) {
            (*spaces)++;            //空格
        } else {
            (*others)++;            //其他字符
        }
    }
}

int main() {
    char str[100];
    int letters, digits, spaces, others;
    
    printf("请输入一个字符串:");
    gets(str);
    
    //传递地址以便修改统计结果
    countCharacters(str, &letters, &digits, &spaces, &others);
    
    printf("统计结果:\n");
    printf("字母:%d个\n", letters);
    printf("数字:%d个\n", digits);
    printf("空格:%d个\n", spaces);
    printf("其他:%d个\n", others);
    
    return 0;
}

10.写一个函数,输入一行字符,将此字符串中最长的单词输出。

cpp 复制代码
#include <stdio.h>
#include <string.h>

//查找最长单词函数
void findLongestWord(char str[], char longestWord[]) {
    int maxLength = 0;          //最长单词长度
    int currentLength = 0;      //当前单词长度
    int start = 0;              //当前单词起始位置
    int maxStart = 0;           //最长单词起始位置
    
    //遍历整个字符串
    for (int i = 0; i <= strlen(str); i++) {
        //遇到字母,当前单词长度增加
        if ((str[i] >= 'A' && str[i] <= 'Z') || (str[i] >= 'a' && str[i] <= 'z')) {
            if (currentLength == 0) {
                start = i;      //记录单词起始位置
            }
            currentLength++;
        }
        //遇到非字母或字符串结束,表示一个单词结束
        else {
            //如果当前单词比之前记录的最长单词更长
            if (currentLength > maxLength) {
                maxLength = currentLength;
                maxStart = start;
            }
            currentLength = 0;  //重置当前单词长度
        }
    }
    
    //复制最长单词到结果数组
    for (int i = 0; i < maxLength; i++) {
        longestWord[i] = str[maxStart + i];
    }
    longestWord[maxLength] = '\0';  //添加结束符
}

int main() {
    char str[200];
    char longestWord[100];
    
    printf("请输入一行字符:");
    gets(str);
    
    findLongestWord(str, longestWord);
    
    if (strlen(longestWord) > 0) {
        printf("最长的单词是:%s\n", longestWord);
        printf("单词长度:%d\n", strlen(longestWord));
    } else {
        printf("没有找到单词!\n");
    }
    
    return 0;
}

11.写一个函数,用"起泡法"对输入的10个字符按由小到大顺序排列。

cpp 复制代码
#include <stdio.h>
#include <string.h>

//起泡法排序函数
void bubbleSort(char arr[]) {
    int n = strlen(arr);
    char temp;
    
    for (int i = 0; i < n - 1; i++) {           //外循环控制排序轮数
        for (int j = 0; j < n - 1 - i; j++) {   //内循环控制每轮比较次数
            if (arr[j] > arr[j + 1]) {          //如果前一个字符大于后一个字符
                //交换两个字符的位置
                temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}

int main() {
    char str[11];
    
    printf("请输入10个字符:");
    scanf("%s", str);
    
    //确保输入了10个字符
    if (strlen(str) != 10) {
        printf("请输入恰好10个字符!\n");
        return 1;
    }
    
    printf("排序前的字符:%s\n", str);
    
    bubbleSort(str);
    
    printf("排序后的字符:%s\n", str);
    
    return 0;
}

12.用牛顿迭代法求根。方程为,系数a, b, c, d的值依次为1, 2, 3, 4,由主函数输入。求x在1附近的一个实根。求出根后由主函数输出。

cpp 复制代码
#include <stdio.h>
#include <math.h>

#define EPS 1e-6       //精度要求
#define MAX_ITER 1000  //最大迭代次数

//原函数 f(x) = ax^3 + bx^2 + cx + d
double f(double x, double a, double b, double c, double d) {
    return a*x*x*x + b*x*x + c*x + d;
}

//导函数 f'(x) = 3ax^2 + 2bx + c
double df(double x, double a, double b, double c) {
    return 3*a*x*x + 2*b*x + c;
}

//牛顿迭代法求根
double newtonMethod(double x0, double a, double b, double c, double d) {
    double x = x0;      //初始值
    double fx, dfx;
    int iter = 0;
    
    do {
        fx = f(x, a, b, c, d);
        dfx = df(x, a, b, c);
        
        if (fabs(dfx) < EPS) {
            printf("导数为0,无法继续迭代\n");
            return x;
        }
        
        x = x - fx / dfx;  //牛顿迭代公式
        iter++;
        
        if (iter > MAX_ITER) {
            printf("超过最大迭代次数\n");
            return x;
        }
        
    } while (fabs(fx) > EPS);  //当函数值足够接近0时停止
    
    printf("迭代次数:%d\n", iter);
    return x;
}

int main() {
    double a, b, c, d;
    double root;
    
    printf("请输入系数a, b, c, d:");
    scanf("%lf%lf%lf%lf", &a, &b, &c, &d);
    
    printf("方程为:%.2fx^3 + %.2fx^2 + %.2fx + %.2f = 0\n", a, b, c, d);
    
    //使用x=1作为初始值,在1附近寻找实根
    root = newtonMethod(1.0, a, b, c, d);
    
    printf("在1附近的实根为:%.6f\n", root);
    printf("f(%.6f) = %.6f\n", root, f(root, a, b, c, d));
    
    return 0;
}

13.用递归方法求n阶勒让德多项式的值,递归公式为

cpp 复制代码
#include <stdio.h>
#include <math.h>

//计算勒让德多项式的递归函数
//n: 多项式阶数
//x: 自变量值
float p(int n, float x) {
    float res;  //存储计算结果
    
    //递归终止条件
    if (n == 0) return 1;          //P0(x) = 1
    if (n == 1) return x;          //P1(x) = x
    
    //递归计算:使用勒让德多项式的递推公式
    //公式:Pn(x) = [(2n-1)*x*P(n-1)(x) - (n-1)*P(n-2)(x)] / n
    if (n > 1) {
        res = ((2 * n - 1) * x * p(n - 1, x) - (n - 1) * p(n - 2, x)) / n;
    }
    return res;
}

int main() {
    int n;      //多项式阶数
    float x;    //自变量
    
    printf("input x,n: ");
    scanf("%f%d", &x, &n); 
    
    //调用函数计算并输出结果
    printf("P%d(%.2f) = %f\n", n, x, p(n, x));
    
    return 0;
}

14.输入10个学生5门课的成绩,分别用函数实现下列功能:

①计算每个学生的平均分;

②计算每门课的平均分;

③找出所有50个分数中最高的分数所对应的学生和课程;

④计算平均分方差

cpp 复制代码
#include <stdio.h>
#define N 10  //学生数
#define M 5   //课程数

//函数声明
void input(float score[N][M]);
void stu_avg(float score[N][M], float sa[N]);
void cou_avg(float score[N][M], float ca[M]);
void find_max(float score[N][M], int *si, int *ci, float *max);
float calc_var(float sa[N]);

int main() {
    float score[N][M];  //成绩
    float sa[N];        //学生平均分
    float ca[M];        //课程平均分
    float max_score;    //最高分
    int max_stu, max_cou; //最高分对应的学生和课程
    float var;          //方差
    
    //1. 输入成绩
    printf("请输入10个学生5门课的成绩:\n");
    input(score);
    
    //2. 计算每个学生的平均分
    stu_avg(score, sa);
    printf("\n每个学生的平均分:\n");
    for (int i = 0; i < N; i++) {
        printf("学生%d: %.2f\n", i+1, sa[i]);
    }
    
    //3. 计算每门课的平均分
    cou_avg(score, ca);
    printf("\n每门课的平均分:\n");
    for (int j = 0; j < M; j++) {
        printf("课程%d: %.2f\n", j+1, ca[j]);
    }
    
    //4. 找出最高分
    find_max(score, &max_stu, &max_cou, &max_score);
    printf("\n最高分信息:\n");
    printf("最高分: %.2f\n", max_score);
    printf("对应学生: 学生%d\n", max_stu+1);
    printf("对应课程: 课程%d\n", max_cou+1);
    
    //5. 计算方差
    var = calc_var(sa);
    printf("\n平均分方差: %.2f\n", var);
    
    return 0;
}

//输入成绩
void input(float score[N][M]) {
    for (int i = 0; i < N; i++) {
        printf("学生%d的5门成绩:", i+1);
        for (int j = 0; j < M; j++) {
            scanf("%f", &score[i][j]);
        }
    }
}

//学生平均分
void stu_avg(float score[N][M], float sa[N]) {
    for (int i = 0; i < N; i++) {
        float sum = 0;
        for (int j = 0; j < M; j++) {
            sum += score[i][j];
        }
        sa[i] = sum / M;
    }
}

//课程平均分
void cou_avg(float score[N][M], float ca[M]) {
    for (int j = 0; j < M; j++) {
        float sum = 0;
        for (int i = 0; i < N; i++) {
            sum += score[i][j];
        }
        ca[j] = sum / N;
    }
}

//找最高分
void find_max(float score[N][M], int *si, int *ci, float *max) {
    *max = score[0][0];
    *si = 0;
    *ci = 0;
    
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            if (score[i][j] > *max) {
                *max = score[i][j];
                *si = i;
                *ci = j;
            }
        }
    }
}

//计算方差
float calc_var(float sa[N]) {
    float sum = 0, mean = 0, var = 0;
    
    //计算平均值
    for (int i = 0; i < N; i++) {
        sum += sa[i];
    }
    mean = sum / N;
    
    //计算方差
    sum = 0;
    for (int i = 0; i < N; i++) {
        sum += (sa[i] - mean) * (sa[i] - mean);
    }
    var = sum / N;
    
    return var;
}

15.写几个函数:

①输入10个职工的姓名和职工号;

②按职工号由小到大顺序排序,姓名顺序也随之调整;

③要求输入一个职工号,用折半查找法找出该职工的姓名,从主函数输入要查找的职工号,输出该职工姓名。

cpp 复制代码
#include <stdio.h>
#include <string.h>
#define N 10  //职工数

//函数声明
void input(int num[], char name[][20]);
void sort(int num[], char name[][20]);
void search(int num[], char name[][20], int target);

int main() {
    int num[N];         //职工号
    char name[N][20];   //职工姓名
    int target;         //要查找的职工号
    
    //1. 输入职工信息
    input(num, name);
    
    //2. 按职工号排序
    sort(num, name);
    
    //3. 输出排序结果
    printf("\n排序后的职工信息:\n");
    for (int i = 0; i < N; i++) {
        printf("职工号:%d  姓名:%s\n", num[i], name[i]);
    }
    
    //4. 折半查找
    printf("\n请输入要查找的职工号:");
    scanf("%d", &target);
    search(num, name, target);
    
    return 0;
}

//输入职工信息
void input(int num[], char name[][20]) {
    printf("请输入%d个职工的信息(职工号 姓名):\n", N);
    for (int i = 0; i < N; i++) {
        printf("职工%d:", i+1);
        scanf("%d %s", &num[i], name[i]);
    }
}

//按职工号排序(冒泡排序)
void sort(int num[], char name[][20]) {
    int temp_num;
    char temp_name[20];
    
    for (int i = 0; i < N-1; i++) {
        for (int j = 0; j < N-1-i; j++) {
            if (num[j] > num[j+1]) {
                //交换职工号
                temp_num = num[j];
                num[j] = num[j+1];
                num[j+1] = temp_num;
                
                //交换姓名
                strcpy(temp_name, name[j]);
                strcpy(name[j], name[j+1]);
                strcpy(name[j+1], temp_name);
            }
        }
    }
}

//折半查找职工
void search(int num[], char name[][20], int target) {
    int low = 0, high = N-1, mid;
    int found = 0;
    
    while (low <= high) {
        mid = (low + high) / 2;
        
        if (num[mid] == target) {
            printf("找到职工:%d %s\n", num[mid], name[mid]);
            found = 1;
            break;
        } else if (num[mid] < target) {
            low = mid + 1;
        } else {
            high = mid - 1;
        }
    }
    
    if (!found) {
        printf("未找到职工号:%d\n", target);
    }
}

16.写一个函数,输入一个十六进制数,输出相应的十进制数。

cpp 复制代码
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <math.h>

//十六进制转十进制函数
int hex_to_dec(char hex[]) {
    int len = strlen(hex);
    int dec = 0;
    int digit, base = 1;
    
    //从最低位开始转换
    for (int i = len - 1; i >= 0; i--) {
        char ch = hex[i];
        
        if (ch >= '0' && ch <= '9') {
            digit = ch - '0';
        } else if (ch >= 'A' && ch <= 'F') {
            digit = ch - 'A' + 10;
        } else if (ch >= 'a' && ch <= 'f') {
            digit = ch - 'a' + 10;
        } else {
            printf("无效的十六进制字符:%c\n", ch);
            return -1;
        }
        
        dec += digit * base;
        base *= 16;  //十六进制基数
    }
    
    return dec;
}

int main() {
    char hex[20];
    int dec;
    
    printf("请输入一个十六进制数:");
    scanf("%s", hex);
    
    dec = hex_to_dec(hex);
    
    if (dec != -1) {
        printf("十六进制 %s = 十进制 %d\n", hex, dec);
    }
    
    return 0;
}

17.用递归法将一个整数n转换成字符串。例如,输入483,应输出字符串"483"。n的位数不确定,可以是任意位数的整数。

cpp 复制代码
#include <stdio.h>

//递归函数:将整数转换为字符串
void int_to_str(int n) {
    if (n < 0) {
        putchar('-');      //输出负号
        n = -n;            //转为正数
    }
    
    if (n / 10 != 0) {      //如果还有高位数字
        int_to_str(n / 10); //递归处理高位
    }
    
    putchar(n % 10 + '0');  //输出当前位数字
}

int main() {
    int n;
    
    printf("请输入一个整数:");
    scanf("%d", &n);
    
    printf("转换后的字符串:");
    int_to_str(n);
    printf("\n");
    
    return 0;
}

18.给出年、月、日,计算该日是该年的第几天。

cpp 复制代码
#include <stdio.h>

//判断是否为闰年
int is_leap(int year) {
    return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}

//计算该日是该年的第几天
int day_of_year(int year, int month, int day) {
    int days = 0;
    
    //每月天数表(非闰年)
    int month_days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    
    //如果是闰年,2月改为29天
    if (is_leap(year)) {
        month_days[1] = 29;
    }
    
    //累加前几个月的天数
    for (int i = 0; i < month - 1; i++) {
        days += month_days[i];
    }
    
    //加上本月的天数
    days += day;
    
    return days;
}

int main() {
    int year, month, day;
    
    printf("请输入年 月 日:");
    scanf("%d %d %d", &year, &month, &day);
    
    //输入验证
    if (year < 1 || month < 1 || month > 12 || day < 1) {
        printf("输入日期无效!\n");
        return 1;
    }
    
    int days = day_of_year(year, month, day);
    printf("%d年%d月%d日是该年的第%d天\n", year, month, day, days);
    
    return 0;
}

一、局部变量和全局变量

局部变量

在一个函数内部定义的变量只在本函数范围内有效,也就是说只有在本函数内才能引用它们,在此函数以外是不能使用这些变量的。在复合语句内定义的变量只在本复合语句范围内有效,只有在本复合语句内才能引用它们。在该复合语句以外是不能使用这些变量的,以上这些称为**"局部变量"**。

全局变量

程序的编译单位是源程序文件,一个源文件可以包含一个或若干个函数。在函数内定义的变量是局部变量,而在函数之外定义的变量称为外部变量 ,外部变量是全局变量(也称全程变量)。全局变量可以为本文件中其他函数所共用。它的有效范围为从定义变量的位置开始到本源文件结束。

二、自动变量(auto变量)、静态局部变量(static局部变量)、寄存器变量(register变量)、外部的 (extern)变量。

自动变量

函数中的局部变量,如果不专门声明为static(静态)存储类别,都是动态地分配存储空间的,数据存储在动态存储区中。函数中的形参和在函数中定义的局部变量(包括在复合语句中定义的局部变量),都属于此类。在调用该函数时,系统会给这些变量分配存储空间,在函数调用结束时就自动释放这些存储空间。因此这类局部变量称为自动变量。自动变量用关键字auto作存储类别的声明。

静态局部变量

有时希望函数中的局部变量的值在函数调用结束后不消失而继续保留原值,即其占用的存储单元不释放,在下一次再调用该函数时,该变量已有值(就是上一次函数调用结束时的值)。这时就应该指定该局部变量为"静态局部变量",用关键字statIc进行声明。

寄存器变量

如果有一些变量使用频繁(例如,在一个函数中执行10000次循环,每次循环中都要引用某局部变量),则为存取变量的值要花费不少时间。为提高执行效率,允许将局部变量的值放在CPU中的寄存器中,需要用时直接从寄存器取出参加运算,不必再到内存中去存取。由于对寄存器的存取速度远高于对内存的存取速度,因此这样做可以提高执行效率。这种变量叫做寄存器变量 。用关键字register作声明。

由于现在的计算机的速度愈来愈快,性能愈来愈高,优化的编译系统能够识别使用频繁的变量,从而自动地将这些变量放在寄存器中,而不需要程序设计者指定。因此,现在实际上用register声明变量的必要性不大。读者只需要知道有这种变量即可,以便在阅读他人写的程序时遇到register时不会感到困惑。

外部变量

1.在一个文件内扩展外部变量的作用域

如果外部变量不在文件的开头定义,其有效的作用范围只限于定义处到文件结束。在定义点之前的函数不能引用该外部变量。如果由于某种考虑,在定义点之前的函数需要引用该外部变量,应该在引用之前用关键字extern对该变量作"外部变量声明",表示把该外部变量的作用域扩展到此位置。有了此声明,就可以从"声明"处起,合法地使用该外部变量。

2.将外部变量的作用域扩展到其他文件

如果一个程序包含两个文件,在两个文件中都要用到同一个外部变量Num,不能分别在两个文件中各自定义一个外部变量Num,否则在进行程序的连接时会出现"重复定义"的错误。正确的做法是:在任一个文件中定义外部变量Num,而在另一文件中用extern对Num作"外部变量声明",即"extern Num;"。在编译和连接时,系统会由此知道Num有"外部链接",可以从别处找到已定义的外部变量Num,并将在另一文件中定义的外部变量Num的作用域扩展到本文件,在本文件中可以合法地引用外部变量Num。

3.将外部变量的作用域限制在本文件中

有时在程序设计中希望某些外部变量只限于被本文件引用,而不能被其他文件引用。这时可以在定义外部变量时加一个static声明。

这种加上static声明、只能用于本文件的外部变量称为静态外部变量。在程序设计中,常由若干人分别完成各个模块,各人可以独立地在其设计的文件中使用相同的外部变量名而互不相干。只须在每个文件中定义外部变量时加上static即可。这就为程序的模块化、通用性提供方便。如果已确认其他文件不需要引用本文件的外部变量,就可以对本文件中的外部变量都加上static,成为静态外部变量,以免被其他文件误用。这就相当于把本文件的外部变量对外界"屏蔽"起来,从其他文件的角度看,这个静态外部变量是"看不见,不能用"的。

用static声明一个变量的作用是:

(1)对局部变量用static声明,把它分配在静态存储区,该变量在整个程序执行期间不释放,其所分配的空间始终存在。

(2)对全局变量用static声明,则该变量的作用域只限于本文件模块(即被声明的文件中)。

三、内部函数和外部函数

函数本质上是全局的,因为定义一个函数的目的就是要被另外的函数调用。如果不加声明的话,一个文件中的函数既可以被本文件中其他函数调用,也可以被其他文件中的函数调用。但是,也可以指定某些函数不能被其他文件调用。根据函数能否被其他源文件调用,将函数区分为内部函数外部函数

内部函数

如果一个函数只能被本文件中其他函数所调用,它称为内部函数 。在定义内部函数时,在函数名和函数类型的前面加static

内部函数又称静态函数,因为它是用static声明的。使用内部函数,可以使函数的作用域只局限于所在文件。这样,在不同的文件中即使有同名的内部函数,也互不干扰,不必担心所用函数是否会与其他文件模块中的函数同名。

通常把只能由本文件使用的函数和外部变量放在文件的开头,前面都冠以static使之局部化,其他文件不能引用。这就提高了程序的可靠性。

外部函数

如果在定义函数时,在函数首部的最左端加关键字extern ,则此函数是外部函数,可供其他文件调用。

C语言规定,如果在定义函数时省略extern,则默认为外部函数。本书前面所用的函数都是外部函数。

在需要调用此函数的其他文件中,需要对此函数作声明(不要忘记,即使在本文件中调用一个函数,也要用函数原型进行声明)。在对此函数作声明时,要加关键字extern,表示该函数"是在其他文件中定义的外部函数"。

相关推荐
不要秃头啊5 小时前
别再谈提效了:AI 时代的开发范式本质变了
前端·后端·程序员
jonjia6 小时前
引入新维度化解权衡难题
程序员
jonjia6 小时前
优秀的工程师如何打破规则
程序员
jonjia6 小时前
在大厂交付大型项目的策略
程序员
jonjia6 小时前
RFC 与设计文档
程序员
jonjia6 小时前
为什么你(或任何人)应该成为一名研发经理?
程序员
jonjia6 小时前
管理技术质量 (Manage Technical Quality)
程序员
jonjia6 小时前
大厂软件工程师职业发展路径
程序员
jonjia6 小时前
关于工程师与影响力
程序员
jonjia6 小时前
多层上下文 (Layers of Context)
程序员