当前位置: 首页 > news >正文

二维字符数组与函数(声明、作用域、生存周期、存储)

1. 二维字符型数组

二维字符数组是C语言中处理字符串数组的常用数据结构,可以看作是一个字符串列表。

1.1 定义与初始化

// 方式1:指定行数和列数 char names[3][10] = {"Alice", "Bob", "Charlie"}; // 方式2:省略行数,由初始化列表决定 char fruits[][8] = {"apple", "banana", "orange"}; // 方式3:逐个字符初始化 char matrix[2][3] = {{'a', 'b', 'c'}, {'d', 'e', 'f'}};

1.2 内存布局与访问

二维字符数组在内存中是连续存储的。对于char arr[3][10],它占用30个连续字节,每行10个字符。

#include <stdio.h> int main() { char cities[3][20] = {"Beijing", "Shanghai", "Guangzhou"}; // 访问单个字符 printf("第一个城市的第一个字符: %c\n", cities[0][0]); // B // 访问整个字符串 printf("第二个城市: %s\n", cities[1]); // Shanghai // 遍历所有字符串 for (int i = 0; i < 3; i++) { printf("城市%d: %s\n", i + 1, cities[i]); } return 0; }

1.3 与指针数组的区别

二维字符数组存储的是实际字符数据,而字符指针数组存储的是字符串常量的地址。

// 二维字符数组 - 可修改内容 char arr[2][10] = {"hello", "world"}; arr[0][0] = 'H'; // 允许修改 // 字符指针数组 - 指向字符串常量 char *ptr_arr[] = {"hello", "world"}; // ptr_arr[0][0] = 'H'; // 错误!试图修改字符串常量

2. 函数的声明与定义

2.1 函数声明(原型)

函数声明告诉编译器函数的名称、返回类型和参数列表,但不包含函数体。

// 函数声明(通常在头文件或文件开头) int add(int a, int b); void print_array(char arr[][10], int rows); double calculate_average(double numbers[], int count);

2.2 函数定义

函数定义包含函数的具体实现。

// 函数定义 int add(int a, int b) { return a + b; } // 处理二维字符数组的函数 void print_strings(char strings[][20], int count) { for (int i = 0; i < count; i++) { printf("字符串%d: %s\n", i + 1, strings[i]); } }

3. 作用域(Scope)

作用域决定了标识符(变量、函数名)在程序中的可见范围。

3.1 局部作用域

void function1() { int x = 10; // x只在function1中可见 printf("x = %d\n", x); } void function2() { // printf("x = %d\n", x); // 错误!x在function2中不可见 int x = 20; // 这是另一个x,与function1中的x无关 }

3.2 全局作用域

#include <stdio.h> int global_var = 100; // 全局变量,从声明处到文件末尾都可见 void func_a() { printf("func_a: global_var = %d\n", global_var); // 可以访问 global_var = 200; // 可以修改 } void func_b() { printf("func_b: global_var = %d\n", global_var); // 可以访问,值为200 } int main() { func_a(); func_b(); return 0; }

3.3 块作用域

int main() { int outer = 5; { int inner = 10; // inner只在这个块内可见 printf("inner = %d\n", inner); printf("outer = %d\n", outer); // 可以访问外层变量 } // printf("inner = %d\n", inner); // 错误!inner已不可见 for (int i = 0; i < 3; i++) { int loop_var = i * 2; // loop_var只在循环体内可见 printf("循环%d: loop_var = %d\n", i, loop_var); } // printf("loop_var = %d\n", loop_var); // 错误! return 0; }

4. 生存周期(Lifetime)

生存周期指变量在内存中存在的时间。

4.1 自动存储期(局部变量)

void demo_auto() { int auto_var = 10; // 进入函数时创建,函数结束时销毁 auto_var++; printf("auto_var = %d\n", auto_var); } // auto_var在这里被销毁 int main() { demo_auto(); demo_auto(); // 每次调用都创建新的auto_var return 0; }

4.2 静态存储期(static变量)

void counter() { static int count = 0; // 只初始化一次,函数结束后仍存在 count++; printf("调用次数: %d\n", count); } int main() { counter(); // 输出: 调用次数: 1 counter(); // 输出: 调用次数: 2 counter(); // 输出: 调用次数: 3 return 0; }

4.3 动态存储期(malloc分配)

#include <stdlib.h> int main() { int *ptr = (int*)malloc(5 * sizeof(int)); // 动态分配内存 if (ptr != NULL) { for (int i = 0; i < 5; i++) { ptr[i] = i * 10; } // 使用完毕后必须手动释放 free(ptr); ptr = NULL; // 避免野指针 } return 0; }

5. 存储类别

5.1 auto(默认)

void func() { auto int x = 10; // auto可省略,默认就是auto int y = 20; // 等价于 auto int y = 20 }

5.2 register

void optimize_loop() { register int i; // 建议编译器将i放入寄存器(编译器可能忽略) for (i = 0; i < 1000000; i++) { // 频繁使用的循环变量 } }

5.3 static

// 文件作用域的static变量 static int file_static = 100; // 只在当前文件可见 void preserve_state() { static char buffer[100]; // 函数调用间保持值 static int initialized = 0; if (!initialized) { strcpy(buffer, "初始值"); initialized = 1; } printf("buffer: %s\n", buffer); }

5.4 extern

// file1.c int global_counter = 0; // file2.c extern int global_counter; // 声明在其他文件中定义的变量 void increment_counter() { global_counter++; }

6. 综合示例:二维字符数组与函数

#include <stdio.h> #include <string.h> // 函数声明 void print_string_array(char arr[][20], int size); void sort_strings(char arr[][20], int size); int find_string(char arr[][20], int size, const char *target); // 全局变量 static int call_count = 0; int main() { char students[][20] = {"ZhangSan", "LiSi", "WangWu", "ZhaoLiu"}; int count = 4; call_count++; printf("=== 程序第%d次运行 ===\n", call_count); printf("原始数组:\n"); print_string_array(students, count); sort_strings(students, count); printf("\n排序后数组:\n"); print_string_array(students, count); int pos = find_string(students, count, "LiSi"); if (pos != -1) { printf("\n找到 LiSi 在位置: %d\n", pos); } return 0; } // 函数定义:打印字符串数组 void print_string_array(char arr[][20], int size) { for (int i = 0; i < size; i++) { printf(" [%d] %s\n", i, arr[i]); } } // 函数定义:冒泡排序字符串数组 void sort_strings(char arr[][20], int size) { char temp[20]; for (int i = 0; i < size - 1; i++) { for (int j = 0; j < size - 1 - i; j++) { if (strcmp(arr[j], arr[j + 1]) > 0) { strcpy(temp, arr[j]); strcpy(arr[j], arr[j + 1]); strcpy(arr[j + 1], temp); } } } } // 函数定义:查找字符串 int find_string(char arr[][20], int size, const char *target) { for (int i = 0; i < size; i++) { if (strcmp(arr[i], target) == 0) { return i; } } return -1; }

7. 关键要点总结

  • 二维字符数组:用于存储多个字符串,内存连续,可修改内容
  • 函数声明:告诉编译器函数接口,便于类型检查
  • 作用域:决定标识符的可见范围(局部、全局、块作用域)
  • 生存周期:决定变量的存在时间(自动、静态、动态)
  • 存储类别:auto(默认)、register、static、extern
  • 最佳实践:合理使用static保持状态,及时释放动态内存

理解这些概念对于编写模块化、可维护的C程序至关重要。二维字符数组结合函数的使用,是处理字符串集合的常见模式。

http://www.cnnetsun.cn/news/3742292.html

相关文章:

  • 大模型上下文长度:原理、挑战与RAG等主流扩展方案详解
  • 3步完成QQ空间历史说说完整备份:GetQzonehistory开源工具终极指南
  • Python编程核心范式:从语法基础到实战项目的100个必背源码精解
  • 2026年静音舱各品牌深度拆解及前景应用
  • Kimi K3开源AI模型许可证政策解析与本地部署指南
  • STM32 ADC多通道采集与DMA应用:从单点到多维信号采集实战
  • FPGA矩阵乘法器设计:从Verilog实现到架构优化
  • Python-openpyxl高级操作
  • 基于51单片机的双通道波形发生器设计:从DAC原理到Proteus仿真
  • HarmonyOS 5.0.0 WebSocket 断线重连怎么写稳:前后台切换、网络变化和消息补偿怎么拆
  • 开源 AI 工具在前端工程中的现实可用性评估:成本、性能与定制化分析
  • 小龙虾Windows版OpenClaw 2026免费下载,配置详解
  • 香橙派/树莓派OpenCV环境搭建:从系统烧录到摄像头测试全攻略
  • BIC建模与法诺共振在电磁仿真中的应用
  • 进程管道通讯-伪终端方式
  • SpringBoot+Vue车辆管理系统毕业设计实战指南
  • LangChain 模型创建与调用实战:从 init_chat_model 到企业级多模型接入
  • Midscene.js终极指南:5分钟用自然语言实现跨平台UI自动化的完整教程
  • C++ std::map排序本质解析:从键排序到值排序的实战指南
  • 2024年C语言学习指南:从零基础到实战进阶
  • Android Gradle构建:自定义APK命名规范与实战配置详解
  • Elasticsearch数据同步接口设计与实现:Python异步批量写入最佳实践
  • 流量重构:从SEO到GEO的“范式转移“
  • Google AI Overviews 搜索变革:从查找工具到解答服务的效率跃迁
  • ppInk:Windows屏幕标注终极解决方案,让你的演示教学效率翻倍
  • 网络编程协议面试经典
  • stm32进入函数一直弹这个
  • React入门:从声明式UI到组件化开发的核心思维与实践
  • OpenResty为什么选择Lua
  • STM32 ADC与DMA高效数据采集:原理、配置与实战避坑指南