C语言进阶指南:从数组、函数到指针与结构体

Finn
Finn
发布时间:2026-10-15| 7人浏览过
原创

C语言作为底层开发的核心语言,其语法简洁但涉及丰富的内存管理概念。本文梳理了C语言第二阶段的几个关键知识点:数组用于存储同类型数据序列,函数实现功能模块化复用,字符串依赖隐式的' '结尾标识。同时深入解析了指针如何作为地址标志操作内存,以及利用struct关键字定义复杂数据模型的方法。

数组与函数封装

当我们需要存储多个相同类型的数据时,可以使用数组(Array)。数组是一组连续内存空间的集合,声明时需指定类型和元素数量。例如:

int arr[10] = {1,2,3,4,5,6,7,8,9,10}; // 定义包含10个整数的数组

若初始化时未明确指定长度,编译器会根据花括号内的元素个数自动推断。数组元素的访问依赖于下标(Index),且C语言中下标严格从0开始。

int main()
{
    int i = 0;
    int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    for (i = 0; i <10; i++)
    {
        printf("%d ", arr[i]);
    }
    printf("\n");
    return 0;
}
为了提升代码的可读性与复用性,我们可以将特定功能封装为函数(Function)。函数的基本结构包含返回类型、函数名、参数列表及函数体。以下示例演示了一个打印1到10数字的无参函数及其调用:
void Print()
{
    for (int i = 0; i < 10; i++)
    {
        printf("%d ", i+1);
    }
}

int main()
{
    Print();
    return 0;
}

字符串存储原理与内存验证

在C语言中,没有独立的字符串数据类型。字符串是通过双引号括起来的字符序列来定义的,如"hello world"。需要注意的是,C语言的字符串在处理时会自动在末尾添加一个空字符 '\0' 作为结束标志。这意味着"hello world"在内存中实际上占用了12个字节(11个可见字符 + 1个'\0')。

为了验证这一特性,我们可以通过对比不同方式定义的字符数组来观察差异:arr1仅包含普通字符而无结束符,arr2显式添加了'\0',而arr3则直接由字符串常量赋值。
#include <stdio.h>
int main()
{
    char arr1[] = { 'a', 'b', 'c', 'd' };
    char arr2[] = { 'a', 'b', 'c', 'd','\0' };
    char* arr3 = "abcd";
    printf("arr1 %s\n", arr1); // 可能引发越界读取,因为缺少\0
    printf("arr2 %s\n", arr2);
    printf("arr3 %s\n", arr3);
    return 0;
}

sizeof 与 strlen 的本质区别

在处理字符串与数组时,sizeof与strlen常被混淆,二者有本质区别:sizeof是关键字,计算的是对象或类型所占用的总字节数;而strlen是标准库函数(头文件<string.h>),专门统计从起始位置到第一个'\0'之前的字符个数。

sizeof 的应用

sizeof可用于计算变量或类型的大小。计算变量时可省略括号,计算类型时必须带括号。如下例所示,即使数组内容相同或未显式分配空间,其大小也由其定义时的初始容量决定。

int main()
{
    char arr1[] = { 'a', 'b', 'c', 'd' };
    char arr2[] = { 'a', 'b', 'c', 'd', '\0' };
    char arr3[10] = { 'a', 'b', 'c', 'd', '\0' };
    printf("arr1 %d\n", sizeof(arr1)); // 结果为 4
    printf("arr2 %d\n", sizeof(arr2)); // 结果为 5
    printf("arr3 %d\n", sizeof(arr3)); // 结果为 10
    return 0;
}
对于类型大小的计算:

int main()
{
    int a = 0;
    printf("int %d\n", sizeof(int));
    printf("a %d\n", sizeof(a));
    return 0;
}
测试不带括号计算变量:

int main()
{
    int a = 0;
    printf("a %d\n", sizeof a);
    return 0;
}
强制要求类型加括号以避免歧义:

int main()
{
    int a = 0;
    // printf("int %d\n", sizeof int); // 错误写法,实际编译会报错或警告,标准建议始终带括号
    // 正确做法:printf("int %d\n", sizeof(int));
    return 0;
}

strlen 的逻辑

>注:此处原文图片展示 strlen 计数逻辑,依赖找到 \0 停止 使用strlen需要引入<string.h>。该函数遍历字符串直到遇到'\0'才结束计数。如果数组中没有'\0',函数将持续向后读取直到碰巧遇到一个值为0的内存单元,这会导致不可预知的结果。
#include <string.h>
int main()
{
    char arr1[] = { 'a', 'b', 'c', 'd' };
    char arr2[] = { 'a', 'b', 'c', 'd', '\0' };
    char* arr3 = "abcd";
    printf("arr1 %d\n", strlen(arr1)); // 危险行为,越界搜索\0
    printf("arr2 %d\n", strlen(arr2)); // 结果为 4
    printf("arr3 %d\n", strlen(arr3)); // 结果为 4
    return 0;
}

转义字符的处理机制

当在字符串中包含特殊符号(如目录路径c:\code\test.c)时,反斜杠\会被解释为转义字符的起始符,导致显示异常。此时需要使用双反斜杠\\来表示真实的反斜杠。

常见转义字符包括:
  • \?:防止三字母词(如??)被解析为])。
  • \\':表示单引号字符。
  • \":表示字符串内部的双引号。
  • \\:表示一个反斜杠。
  • \n, \t, \r等:控制输出格式。
  • \ddd(八进制)与\xdd(十六进制):表示特定ASCII值。
了解转义机制有助于正确解析字符串长度。例如,字符串"c:\\test\\328\\test.c",其中的\t会被视为水平制表符,\32被视为八进制转义,最终通过strlen获取的长度并非直观看到的字符数。

基础控制流:选择与循环

C语言的控制流主要通过算数、逻辑、位运算等操作符结合条件判断来实现。其中逗号表达式从左向右依次执行,整个表达式的值是最后一项的值。

if-else 多分支判断

通过输入数值进行决策,是程序交互的基础。支持使用else if扩展判断条件。注意,else总是与距离它最近的未匹配的if配对。

switch-case 离散条件处理

switch适用于基于整数类型(如char, int)的多分支跳转。每个case块结束后通常需接break以跳出循环,否则会发生“穿透”效应,继续执行下一个case的代码直至遇到break或结束。default块处理所有未匹配的情况。 无break导致的穿透现象演示:

循环结构分为三种:
  1. for循环:适合已知循环次数的场景。先执行初始化,再判断条件,最后执行调整步长。
  1. while循环:先判断后执行。如果初始条件不满足,循环体一次也不会执行。
  1. do...while循环:先执行一次循环体,再进行条件判断,至少执行一次。
在循环内部,可使用continue跳过本次剩余代码进入下一轮迭代,或使用break彻底终止当前循环。

指针:内存访问的桥梁

指针是指向内存地址的变量。无论指针指向何种数据类型,其在32位系统中大小为4字节,在64位系统中大小为8字节。这是由系统寻址能力决定的。

通过解引用操作符*,可以访问指针所指向地址处的实际数据。修改解引用的值即等同于修改原变量的值。
int main()
{
    int a = 10;
    int * p = &a; // p 存的是 a 的地址
    printf("a = %d\n", *p); // 读取 a 的值
    *p = 20;  // 通过指针修改 a 的值
    printf("a = %d\n", a);
    return 0;
}
尽管指针指向不同类型(如int*, char*, double*, 甚至struct Student*),但只要运行环境固定(如均为64位机器),这些指针变量本身的大小是相同的。

自定义类型 struct 结构体

>注:原文此处标题误写为自定义类型,实为结构体struct的具体应用 当需要描述一组相关但类型不同的属性(如学生的姓名、性别、年龄)时,可使用结构体(Structure)将不同数据类型打包在一起。关键字为struct。 结构体的定义形式:

struct 结构体名字
{
    成员类型 成员名;
    ... 
};
使用示例:

struct Student
{
    char name[100];
    char sex[10];
    int age;
};

int main()
{
    struct Student stu = { "张三", "男", 18};
    printf("%s %s %d\n", stu.name, stu.sex, stu.age);
    return 0;
}
以上就是C语言核心基础知识的详细内容,更多关于C语言进阶技巧的资料请关注本站其它相关文章!
相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。