C 语言编程教程

C 语言 - 首页

C 语言基础

C 语言 - 概述 C 语言 - 特性 C 语言 - 发展历史 C 语言 - 环境设置 C 语言 - 程序结构 C 语言 - Hello World C - 编译过程 C - 注释 C - 标记 C - 关键字 C - 标识符 C - 用户输入 C - 基本语法 C - 数据类型 C - 变量 C - 整数提升 C - 类型转换 C - 类型转换 C - 布尔值

C 语言中的常量和文字

C - 常量 C - 字面量 C - 转义序列 C - 格式说明符

C 语言中的运算符

C - 运算符 C - 算术运算符 C - 关系运算符 C - 逻辑运算符 C - 位运算符 C - 赋值运算符 C - 一元运算符 C - 递增和递减运算符 C - 三元运算符 C - sizeof 运算符 C - 运算符优先级 C - 其他运算符

C 语言中的决策

C - 决策 C - if 语句 C - if...else 语句 C - 嵌套 if 语句 C - switch 语句 C - 嵌套 switch 语句

C 语言中的循环

C - 循环 C - While 循环 C - For 循环 C - Do...while 循环 C - 嵌套循环 C - 无限循环 C - Break 语句 C - Continue 语句 C - goto 语句

C 语言中的函数

C - 函数 C - Main 函数 C - 按值调用函数 C - 按引用调用函数 C - 嵌套函数 C - 可变参数函数 C - 用户定义函数 C - 回调函数 C - return 语句 C - 递归

C 语言中的作用域规则

C - 作用域规则 C - 静态变量 C - 全局变量

C 语言中的数组

C - 数组 C - 数组的属性 C - 多维数组 C - 将数组传递给函数 C - 从函数返回数组 C - 可变长度数组

C 语言中的指针

C - 指针 C - 指针和数组 C - 指针的应用 C - 指针运算 C - 指针数组 C - 指向指针的指针 C - 将指针传递给函数 C - 从函数返回指针 C - 函数指针 C - 指向数组的指针 C - 指向结构体的指针 C - 指针链 C - 指针 vs 数组 C - 字符指针和函数 C - NULL 指针 C - void 指针 C - 悬垂指针 C - 解引用指针 C - Near、Far 和 Huge 指针 C - 指针数组的初始化 C - 指针与多维数组

C 语言中的字符串

C - 字符串 C - 字符串数组 C - 特殊字符

C 语言的结构体和联合

C - 结构体 C - 结构体和函数 C - 结构体数组 C - 自引用结构 C - 查找表 C - 点 (.) 运算符 C - 枚举(或 enum) C - 结构填充和打包 C - 嵌套结构 C - 匿名结构和联合 C - 联合 C - Bit 位字段 C - Typedef

C 语言中的文件处理

C - 输入和输出 C - 文件 I/O(文件处理)

C 语言中的预处理器

C - 预处理器 C - #pragma 编译指示 C - 预处理器操作符 C - 宏 C - 头文件

C 语言中的内存管理

C - 内存管理 C - 内存地址 C - 存储类

C 其他主题

C - 错误处理 C - 可变参数 C - 命令执行 C - 数学函数 C - static 静态关键字 C - 随机数生成 C - 命令行参数

C 语言编程资源

C语言问题与解答答案 C语言快速指南 C语言速查表 C语言实用资源 C语言讨论


C 语言中指针的应用

C 语言最重要的特性之一是它通过指针的概念提供低级内存访问。指针是一个变量,用于存储内存中另一个变量的地址。

指针有很多应用,例如将数组和结构体类型传递给函数,以及动态内存分配等。在本章中,我们将讲解 C 语言中指针的一些重要应用。

访问数组元素

数组元素也可以通过指针访问。您需要声明并初始化一个指向数组的指针,并通过将指针变量递增1来访问每个元素。

指向数组的指针是其第0个元素的地址。当数组指针递增1时,它指向数组中的下一个元素。

示例

以下示例演示了如何借助指针遍历数组。

#include <stdio.h>

int main(){

   int arr[] = {1,2,3,4,5};
   int *ptr = arr;

   for(int i = 0; i <= 4; i++){
      printf("arr[%d]: %d
", i, *ptr);
      ptr++;
   }
   
   return 0;
}

输出

运行代码并检查其输出 −

arr[0]: 1
arr[1]: 2
arr[2]: 3
arr[3]: 4
arr[4]: 5

动态分配内存

C 语言指针最重要的应用之一是动态地为变量声明内存。在很多情况下,静态内存分配无法解决问题,例如处理大尺寸数组、包含 n 个学生和员工的结构体等等。

因此,每当您需要动态分配内存时,指针都扮演着重要的角色。C 语言提供了一些动态分配和释放内存的函数。这些函数包括:

  1. malloc() 函数
    分配一个包含 num 个元素的数组,每个元素的大小为 size(以字节为单位)。
  2. calloc() 函数
    分配一个 num 字节数组,并使其保持未初始化状态。
  3. realloc() 函数
    重新分配内存,将其扩展到 newsize。

1. malloc() 函数

此函数定义在"stdlib.h"头文件中。它分配所需大小的内存块,并返回一个 void 指针。

void *malloc (size)

size 参数指的是内存块(以字节为单位)。要为指定的数据类型分配所需的内存,您需要使用类型转换运算符。例如,以下代码片段分配了存储 int 类型所需的内存。

int *ptr;
ptr = (int * ) malloc (sizeof (int));

这里我们需要定义一个指向字符的指针,但不定义所需的内存大小,之后根据需要分配内存。

示例

在此示例中,我们使用 malloc() 函数分配所需的内存来存储字符串(而不是声明一个固定大小的 char 数组)-

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(){

   char *name;
   name = (char *) malloc(strlen("TutorialsPoint"));

   strcpy(name, "TutorialsPoint");
   
   if(name == NULL) {
      fprintf(stderr, "Error - unable to allocate required memory
");
   } else {
      printf("Name = %s
", name );
   }
}

输出

当编译并执行上述代码时,它会产生以下输出 -

Name = TutorialsPoint

2. calloc() 函数

C 库函数 "calloc"(代表连续分配)分配请求的内存并返回指向该内存的指针。

void *calloc(n, size);

其中 "n" 是待分配元素的数量,"size" 是每个元素的字节大小。

以下代码片段分配了存储 10 个整数类型所需的内存。

int *ptr;
ptr = (int *) calloc(25, sizeof(int));

3. realloc() 函数

C 语言中的 realloc() 函数用于动态更改先前分配内存的分配。您可以通过调用 realloc() 函数来增加或减少已分配内存块的大小。

void *realloc(*ptr, size);

第一个参数"ptr"是指向先前使用malloc、callocrealloc分配的内存块的指针,该内存块将被重新分配。

动态内存分配技术广泛应用于操作系统软件中使用的复杂线性和非线性数据结构,例如链表和树。

将参数作为引用传递

当通过引用调用函数时,传递的是实际参数变量的地址,而不是它们的值。

将指针传递给函数有两个优点

首先,它克服了按值传递的局限性。对被调用函数内部值的更改直接在指针中存储的地址上进行。因此,我们可以从一个作用域操作另一个作用域中的变量。

其次,它还克服了函数只能返回一个表达式的限制。通过传递指针,函数的执行效果直接在地址处进行。其次,如果我们返回数组或结构体变量的指针,则可以返回多个值。

示例

以下函数接收两个要交换值的变量的引用。

/* 函数定义用于交换值 */

int swap(int *x, int *y){
    int z;
    z = *x; /* 将值保存在地址 x */
    *x = *y; /* 将 y 放入 x */
    *y = z; /* 将 z 放入 y */
    
    return 0;
}

示例

main() 函数有两个变量"a"和"b",它们的地址作为参数传递给 swap() 函数。

#include <stdio.h>

int swap(int *x, int *y);

int main(){

   /* 局部变量定义 */
   int a = 10;
   int b = 20;
 
   printf("Before swap, value of a : %d
", a);
   printf("Before swap, value of b : %d
", b);
 
   /* calling a function to swap the values */
   swap(&a, &b);
 
   printf("After swap, value of a: %d
", a);
   printf("After swap, value of b: %d
", b);
 
   return 0;
}

输出

执行时,它将产生以下输出 -

Before swap, value of a: 10
Before swap, value of b: 20
After swap, value of a: 20
After swap, value of b: 10

在此程序中,我们能够在函数作用域之外交换两个变量的值,并且克服了函数只能传递一个表达式的限制。

将数组传递给函数

让我们利用这些特性通过引用传递数组。在 main() 函数中,我们声明一个数组并将其地址传递给 max() 函数。

max() 函数使用指针遍历数组,并将数组中的最大数字返回给 main() 函数。

示例

请看以下示例 -

#include <stdio.h>

int max(int *arr, int length);

int main(){
    
   int arr[] = {10, 34, 21, 78, 5};
   int length = sizeof(arr)/sizeof(int);

   int maxnum = max(arr, length);
      printf("max: %d", maxnum);
}

int max(int *arr, int length){

   int max = *arr;
        
   for (int i = 0; i < length; i++){   
      printf("arr[%d]: %d
", i, (*arr));
        
      if ((*arr)>max)
         max = (*arr);
      arr++;
   }
   return max;
}

输出

运行代码并检查其输出 −

arr[0]: 10
arr[1]: 34
arr[2]: 21
arr[3]: 78
arr[4]: 5
max: 78

max() 函数从 main() 函数中接收数组的地址,该地址存储在指针 "arr" 中。每次递增时,它都指向原始数组中的下一个元素。

函数返回多个值

在 C 语言中,函数只能有一个 return 语句,每次返回一个值。借助 C 指针,您可以通过将参数作为引用传递来从函数返回多个值。

示例

以下示例演示了如何借助 C 指针返回多个值。

#include <stdio.h>

// 创建一个函数来计算
// 两个数的加法和减法
void funAddSub(int a, int b, int* add, int* sub) {
  *add = a + b;
  *sub = a - b;
}

int main() {
    int num1 = 10;
    int num2 = 3;
    
    // 存储结果的变量
    int res1, res2;
    
    // 调用函数获取 add 和 sub 操作
    // 通过传递 res1 和 res2 的地址
    funAddSub(num1, num2, &res1, &res2);
    
    // 打印结果
    printf("Addition is %d and subtraction is %d", res1, res2);
    
    return 0;
}

输出

Addition is 13 and subtraction is 7