C语言作用域与数组详解

作用域

作用域是程序中的一个区域,在该区域内定义的变量可以被访问,超出该区域则无法访问。在C语言中,变量可以在三个地方声明:

1. 局部变量

在函数或块内部声明的变量称为局部变量。

特点:

  • 只能被该函数或代码块中的语句使用

  • 在函数外部不可见

  • 生命周期仅限于函数执行期间

示例:

c

复制代码
#include <stdio.h>

int main() {
    /* 局部变量声明 */
    int a, b;
    int c;
    
    /* 实际初始化 */
    a = 10;
    b = 20;
    c = a + b;
    
    printf("value of a = %d, b = %d and c = %d\n", a, b, c);
    
    return 0;
}

2. 全局变量

在所有函数外部定义的变量称为全局变量。

特点:

  • 在程序的整个生命周期中都保留其值

  • 可以被程序中的任何函数访问

  • 在声明之后,在整个程序中可用

示例:

c

复制代码
#include <stdio.h>

/* 全局变量声明 */
int g;

int main() {
    /* 局部变量声明 */
    int a, b;
    
    /* 实际初始化 */
    a = 10;
    b = 20;
    g = a + b;
    
    printf("value of a = %d, b = %d and g = %d\n", a, b, g);
    
    return 0;
}

3. 形式参数

函数参数定义中的变量称为形式参数。

特点:

  • 在函数中被视为局部变量

  • 优先于全局变量

示例:

c

复制代码
#include <stdio.h>

/* 全局变量声明 */
int a = 20;

int main() {
    /* main函数中的局部变量声明 */
    int a = 10;
    int b = 20;
    int c = 0;

    printf("value of a in main() = %d\n", a);
    c = sum(a, b);
    printf("value of c in main() = %d\n", c);

    return 0;
}

/* 相加两个整数的函数 */
int sum(int a, int b) {
    printf("value of a in sum() = %d\n", a);
    printf("value of b in sum() = %d\n", b);

    return a + b;
}

作用域优先级规则

当局部变量和全局变量同名时:

  • 局部变量优先于全局变量

  • 形式参数优先于全局变量

示例:

c

复制代码
#include <stdio.h>

/* 全局变量声明 */
int g = 20;

int main() {
    /* 局部变量声明 */
    int g = 10;
    
    printf("value of g = %d\n", g);  // 输出10,局部变量优先
    
    return 0;
}

变量初始化

局部变量:

  • 系统不会自动初始化

  • 必须手动初始化,否则包含垃圾值

全局变量:

  • 系统自动初始化

  • 初始化规则:

    • int 类型初始化为 0

    • char 类型初始化为 '\0'

    • float 类型初始化为 0

    • double 类型初始化为 0

    • 指针类型初始化为 NULL

良好实践: 总是初始化变量,避免不可预知的结果。


数组

数组是一种数据结构,可以存储相同类型元素的固定大小顺序集合。

1. 数组声明

语法:

c

复制代码
type arrayName[arraySize];

示例:

c

复制代码
double balance[10];  // 声明一个包含10个double类型元素的数组

2. 数组初始化

方式1:声明时初始化

c

复制代码
double balance[5] = {1000.0, 2.0, 3.4, 7.0, 50.0};

方式2:省略大小(自动计算)

c

复制代码
double balance[] = {1000.0, 2.0, 3.4, 7.0, 50.0};

方式3:单独赋值

c

复制代码
balance[4] = 50.0;  // 为第5个元素赋值

数组索引:

  • 第一个元素索引为0(基索引)

  • 最后一个元素索引为数组大小减1

3. 访问数组元素

示例:

c

复制代码
#include <stdio.h>

int main() {
    int n[10];  // n是包含10个整数的数组
    int i, j;
    
    /* 初始化数组元素为0 */         
    for(i = 0; i < 10; i++) {
        n[i] = i + 100;  // 设置位置i的元素为i + 100
    }
    
    /* 输出每个数组元素的值 */
    for(j = 0; j < 10; j++) {
        printf("Element[%d] = %d\n", j, n[j]);
    }
    
    return 0;
}

4. 多维数组

C语言支持多维数组,最常见的是二维数组。

声明语法:

c

复制代码
type arrayName[x][y];  // 二维数组
type arrayName[x][y][z];  // 三维数组

二维数组初始化:

c

复制代码
// 方式1:明确分行初始化
int a[3][4] = {  
    {0, 1, 2, 3},   // 第0行的初始化
    {4, 5, 6, 7},   // 第1行的初始化
    {8, 9, 10, 11}  // 第2行的初始化
};

// 方式2:连续初始化
int a[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};

访问二维数组元素:

c

复制代码
int val = a[2][3];  // 获取第3行第4列的元素

二维数组示例:

c

复制代码
#include <stdio.h>

int main() {
    /* 一个5行2列的数组 */
    int a[5][2] = { {0,0}, {1,2}, {2,4}, {3,6}, {4,8} };
    int i, j;
    
    /* 输出每个数组元素的值 */
    for(i = 0; i < 5; i++) {
        for(j = 0; j < 2; j++) {
            printf("a[%d][%d] = %d\n", i, j, a[i][j]);
        }
    }
    
    return 0;
}

5. 数组作为函数参数

三种声明方式:

方式1:指针作为形式参数

c

复制代码
void myFunction(int *param) {
    // 函数体
}

方式2:指定数组大小

c

复制代码
void myFunction(int param[10]) {
    // 函数体
}

方式3:不指定数组大小

c

复制代码
void myFunction(int param[]) {
    // 函数体
}

实际示例:

c

复制代码
#include <stdio.h>

/* 函数声明 */
double getAverage(int arr[], int size);

int main() {
    /* 包含5个元素的int数组 */
    int balance[5] = {1000, 2, 3, 17, 50};
    double avg;
    
    /* 传递数组指针作为参数 */
    avg = getAverage(balance, 5);
    
    /* 输出返回值 */
    printf("Average value is: %f\n", avg);
    
    return 0;
}

/* 计算平均值的函数 */
double getAverage(int arr[], int size) {
    int i;
    double avg;
    double sum = 0;
    
    for(i = 0; i < size; ++i) {
        sum += arr[i];
    }
    
    avg = sum / size;
    return avg;
}

6. 从函数返回数组

C语言不允许直接返回整个数组,但可以返回指向数组的指针。

重要注意事项:

  • 不能返回局部变量的地址

  • 必须将局部变量声明为static

示例:

c

复制代码
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

/* 生成并返回随机数的函数 */
int *getRandom() {
    static int r[10];
    int i;
    
    /* 设置种子 */
    srand((unsigned)time(NULL));
    
    for(i = 0; i < 10; ++i) {
        r[i] = rand();
        printf("r[%d] = %d\n", i, r[i]);
    }
    
    return r;
}

/* 主函数 */
int main() {
    int *p;  // 指向int的指针
    int i;
    
    p = getRandom();
    
    for(i = 0; i < 10; i++) {
        printf("*(p + %d) : %d\n", i, *(p + i));
    }
    
    return 0;
}

7. 指向数组的指针

数组名是指向数组第一个元素的常量指针。

重要概念:

  • balance 指向 &balance[0]

  • *(balance + 4) 等同于 balance[4]

示例:

c

复制代码
#include <stdio.h>

int main() {
    /* 包含5个元素的数组 */
    double balance[5] = {1000.0, 2.0, 3.4, 17.0, 50.0};
    double *p;
    int i;
    
    p = balance;  // p指向数组的第一个元素
    
    /* 使用指针输出数组元素的值 */
    printf("Array values using pointer\n");
    for(i = 0; i < 5; i++) {
        printf("*(p + %d) : %f\n", i, *(p + i));
    }
    
    /* 使用数组名作为地址输出数组元素的值 */
    printf("Array values using balance as address\n");
    for(i = 0; i < 5; i++) {
        printf("*(balance + %d) : %f\n", i, *(balance + i));
    }
    
    return 0;
}

总结

  1. 作用域规则

    • 局部变量只在定义它们的函数或块中可见

    • 全局变量在整个程序中可见

    • 形式参数在函数中作为局部变量处理

  2. 数组特性

    • 存储相同类型元素的集合

    • 支持一维和多维数组

    • 可以通过指针操作

    • 可以作为函数参数传递

    • 可以通过返回指针从函数返回

  3. 最佳实践

    • 总是初始化变量

    • 注意数组边界,避免越界访问

    • 理解指针和数组的关系

    • 在多维数组中正确使用嵌套循环

掌握作用域和数组的概念对于编写结构良好、高效的C语言程序至关重要。

相关推荐
想唱rap2 小时前
直接选择排序、堆排序、冒泡排序
c语言·数据结构·笔记·算法·新浪微博
老葱头蒸鸡3 小时前
(27)APS.NET Core8.0 堆栈原理通俗理解
算法
视睿3 小时前
【C++练习】06.输出100以内的所有素数
开发语言·c++·算法·机器人·无人机
草莓熊Lotso3 小时前
从 “Hello AI” 到企业级应用:Spring AI 如何重塑 Java 生态的 AI 开发
java·人工智能·经验分享·后端·spring
doulbQuestion3 小时前
【无标题】
java·spring
Metaphor6924 小时前
Java 旋转 PDF 页面:使用 Spire.PDF 实现高效页面处理
java·经验分享·pdf
柠檬07114 小时前
matlab cell 数据转换及记录
算法
哈利路亚胡辣汤4 小时前
spring多数据源配置
java·spring·mybatis
卷Java4 小时前
智慧停车大屏数据分析与设计文档
java·大数据·人工智能·数据分析