29. C語言 可變參數詳解

本章目錄:

    • 前言
    • 可變參數的基本概念
      • 可變參數的工作原理
      • 如何使用可變參數
    • 示例:計算多個整數的平均值
      • 解析:
    • 更復雜的可變參數示例:打印可變數量的字符串
      • 解析:
    • 總結


前言

在C語言中,函數參數的數量通常是固定的,但在某些情況下,我們可能需要一個函數能夠接受不同數量的參數。為了應對這一需求,C語言提供了可變參數機制,這使得函數的參數個數能夠靈活調整。這在處理不確定參數個數的場景中非常有用,比如打印調試信息、構建日志記錄函數等。


可變參數的基本概念

C語言允許函數定義具有可變數量的參數,形式如下所示:

int func_name(int arg1, ...);

其中,...表示該函數的可變參數列表。與固定參數不同,C語言并不直接提供有關可變參數的類型和個數的直接信息,因此我們需要一些宏和類型來處理這些參數。

可變參數的工作原理

要在C語言中使用可變參數,我們必須引入<stdarg.h>頭文件。該頭文件定義了一些用于處理可變參數的宏。這些宏使得程序能夠訪問可變參數列表,并從中獲取不同類型的參數。

常用的宏有:

  • va_list:該類型用于保存可變參數的相關信息。
  • va_start(ap, last_arg):初始化va_list變量,指向第一個可變參數。
  • va_arg(ap, type):訪問可變參數列表中的下一個參數,并將ap指向下一個參數。
  • va_end(ap):結束可變參數的訪問。

如何使用可變參數

  1. 定義一個va_list變量:該變量用于保存參數信息。
  2. 使用va_start初始化:該宏初始化va_list變量,使其指向可變參數的第一個元素。
  3. 使用va_arg獲取每一個參數:每次調用va_arg獲取一個參數,并使指針指向下一個參數。
  4. 使用va_end結束訪問:訪問結束后,需要使用va_end來清理資源。

讓我們通過一個示例來詳細說明這一過程。

示例:計算多個整數的平均值

下面是一個函數average,它接受多個整數作為參數,并計算這些整數的平均值。

#include <stdio.h>
#include <stdarg.h>// 計算平均值的函數
double average(int num, ...) {va_list valist;     // 聲明一個va_list變量,用于保存可變參數的信息double sum = 0.0;   // 用于累加所有參數的和int i;// 初始化valist,num是可變參數前的固定參數va_start(valist, num);// 逐一獲取并累加參數for (i = 0; i < num; i++) {sum += va_arg(valist, int); // 獲取下一個整數并累加}// 清理valistva_end(valist);return sum / num;  // 返回平均值
}int main() {// 調用average函數,傳入不同數量的參數printf("Average of 2, 3, 4, 5 = %f\n", average(4, 2, 3, 4, 5));printf("Average of 5, 10, 15 = %f\n", average(3, 5, 10, 15));return 0;
}

解析:

  1. average函數:該函數接受一個固定的參數num,表示后面可變參數的個數。通過va_start宏初始化valist,然后通過va_arg宏逐個訪問參數并進行累加。
  2. va_start(valist, num):初始化valistnum是最后一個固定參數的名字,告訴va_start從哪里開始讀取可變參數。
  3. va_arg(valist, int):每次調用時,va_arg都會返回一個參數的值,并使valist指向下一個參數。
  4. va_end(valist):結束對valist的訪問,釋放資源。

運行此程序的輸出結果是:

Average of 2, 3, 4, 5 = 3.500000
Average of 5, 10, 15 = 10.000000

更復雜的可變參數示例:打印可變數量的字符串

我們可以進一步擴展可變參數的應用,例如設計一個函數,它能夠接受任意數量的字符串并逐一打印它們。以下是實現的代碼:

#include <stdio.h>
#include <stdarg.h>
#include <string.h>// 打印多個字符串
void print_strings(const char* msg, ...) {va_list argp;int argno = 1; // 參數編號char *str;// 初始化va_listva_start(argp, msg);// 輸出第一個固定參數printf("%s: ", msg);// 逐個取出字符串并打印while (1) {str = va_arg(argp, char*);if (strcmp(str, "/0") == 0) break;  // "/0"表示參數輸入結束printf("Parameter #%d is: %s\n", argno, str);argno++;}// 清理va_listva_end(argp);
}int main() {print_strings("Demo", "This", "is", "a", "test", "/0");return 0;
}

解析:

  1. print_strings函數:此函數接受一個固定參數msg,表示信息的前綴。接下來的可變參數是字符串,直到遇到特殊字符串/0為止,表示參數輸入的結束。
  2. va_list的使用:函數通過va_start初始化參數列表,然后使用va_arg逐一獲取并打印每個字符串,直到遇到/0
  3. va_end:結束對可變參數的訪問,釋放資源。

運行此代碼的輸出如下:

Demo: Parameter #1 is: This
Parameter #2 is: is
Parameter #3 is: a
Parameter #4 is: test

總結

可變參數在C語言中提供了極大的靈活性,使得函數能夠接受不同數量的參數。通過使用stdarg.h中的宏,我們可以安全地訪問和處理這些參數。在實際應用中,理解和掌握可變參數的使用對于編寫更加通用的庫和函數非常重要。

在實際編程中,我們應注意以下幾點:

  1. 可變參數的類型安全:C語言并不進行類型檢查,因此在使用va_arg時需要確保獲取的參數類型正確。
  2. 參數個數的傳遞:可變參數列表并不自帶參數個數,因此通常需要通過固定參數來傳遞參數的數量,或者通過特定的標志符(如/0)來終止參數的讀取。

通過掌握這些知識,您可以更靈活地處理函數參數,編寫更加高效和可復用的代碼。


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/67435.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/67435.shtml
英文地址,請注明出處:http://en.pswp.cn/web/67435.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

RoboMaster- RDK X5能量機關實現案例(一)識別

作者&#xff1a;SkyXZ CSDN&#xff1a;https://blog.csdn.net/xiongqi123123 博客園&#xff1a;https://www.cnblogs.com/SkyXZ 在RoboMaster的25賽季&#xff0c;我主要負責了能量機關的視覺方案開發&#xff0c;目前整體算法已經搭建完成&#xff0c;實際方案上我使用的上…

shell腳本批量修改文件名之方法(The Method of Batch Modifying File Names in Shell Scripts)

shell腳本批量修改文件名方法 我們可以使用Shell腳本來實現這個功能。Shell腳本是一種用于自動化任務的編程語言&#xff0c;它可以在Unix/Linux操作系統上運行。在這個腳本中&#xff0c;我們將使用一個for循環來遍歷目標目錄下的所有文件&#xff0c;并使用mv命令將每個文件…

MySQL誤刪數據怎么辦?

文章目錄 1. 從備份恢復數據2. 通過二進制日志恢復數據3. 使用數據恢復工具4. 利用事務回滾恢復數據5. 預防誤刪數據的策略總結 在使用MySQL進行數據管理時&#xff0c;誤刪數據是一個常見且具有高風險的操作。無論是因為操作失誤、系統故障&#xff0c;還是不小心執行了刪除命…

RDK X5運行DeepSeek-R1-Distill-Qwen-1.5B,體驗長思維鏈的語言大模型!

簡介 本文介紹了在RDK X5上&#xff0c;如何從HuggingFace的原始模型權重&#xff08;safetensors&#xff09;經過量化和編譯&#xff0c;的到llama.cpp推理框架所需要的GGUF格式的模型&#xff0c;然后演示了如何使用llama.cpp運行量化后的DeepSeek-R1-Distill-Qwen-1.5B模型…

SQL UCASE() 函數詳解

SQL UCASE() 函數詳解 在SQL中&#xff0c;UCASE() 函數是一個非常有用的字符串處理函數&#xff0c;它可以將字符串中的所有小寫字母轉換為大寫字母。本文將詳細介紹UCASE() 函數的用法、語法、示例以及其在實際應用中的優勢。 一、UCASE() 函數簡介 UCASE() 函數是SQL標準…

【Proteus仿真】【51單片機】簡易計算器系統設計

目錄 一、主要功能 二、使用步驟 三、硬件資源 四、軟件設計 五、實驗現象 聯系作者 一、主要功能 1、LCD1602液晶顯示 2、矩陣按鍵? 3、可以進行簡單的加減乘除運算 4、最大 9999*9999 二、使用步驟 系統運行后&#xff0c;LCD1602顯示數據&#xff0c;通過矩陣按鍵…

留學畢業論文如何利用不同問題設計問卷

在留學畢業論文的寫作中&#xff0c;我們經常會遇到各種問題&#xff0c;例如選擇合適的問題&#xff0c;選擇合適的研究方法&#xff0c;以及設計合理的研究過程。然而在完成留學畢業論文的過程中&#xff0c;我們往往會在研究設計這里卡住。即使我們選準了研究問題和研究方法…

深度學習在金融風控中的應用:突破傳統模型的瓶頸

深度學習在金融風控中的應用:突破傳統模型的瓶頸 金融風險控制(簡稱“風控”)是現代金融體系中至關重要的一環,關系到金融機構的穩定性、客戶的安全以及整體經濟的健康運行。近年來,隨著深度學習的迅猛發展,傳統的風控模型正面臨被顛覆的挑戰,新的技術手段和思維方式正…

Python中的函數(上)

Python中的函數是非常重要的編程概念&#xff0c;以下是詳細的介紹&#xff1a; 函數定義基礎 在Python中&#xff0c;函數是組織好的、可重復使用的代碼塊&#xff0c;用于執行特定任務。通過函數&#xff0c;我們可以將復雜的程序分解為較小的、更易管理的部分&#xff0c…

圖漾相機搭配VisionPro使用簡易教程

文章目錄 1.下載并安裝VisionPro軟件2.下載PercipioCameraForVisionPro軟件包3.軟件部署4.測試流程4.1 遍歷VisionPro SDK支持的參數4.2 設置示例4.2.1_cameraSingle.SetTriggerMode4.2.2 _cameraSingle.SetRegistration4.2.3_cameraSingle.SetInt4.2.4 _cameraSingle.GetInt4.…

新版IDEA創建數據庫表

這是老版本的IDEA創建數據庫表&#xff0c;下面可以自己勾選Not null&#xff08;非空),Auto inc&#xff08;自增長),Unique(唯一標識)和Primary key&#xff08;主鍵) 這是新版的IDEA創建數據庫表&#xff0c;Not null和Auto inc可以看得到&#xff0c;但Unique和Primary key…

(非技術)從一公里到半程馬拉松:我的一年跑步經歷

在24年初&#xff0c;從來不運動的我&#xff0c;連跑步一公里都不能完成。而在一年之后的2025年的1月1日&#xff0c;我參加了上海的蒸蒸日上迎新跑&#xff0c;完成了半程馬拉松。雖然速度不快&#xff0c;也并不是什么特別難完成的事情&#xff0c;但對我來說還是挺有意義的…

論“0是不存在的”

你看這又是一個悖論的例子。 你會說&#xff0c;既然你都寫出來了“0”&#xff0c;咋還能說它不存在&#xff1f; 總是刷到謝爾頓說零不存在那個視頻。可能有些小伙伴不解其意&#xff0c;為啥那小謝爾頓堅持說0不存在。我這說一個最簡單的視角&#xff0c;怎么理解這句話。…

電商系統-用戶認證(三)基于公鑰解析JWT令牌

一、 基于私鑰生成jwt令牌 步驟&#xff1a; 導入認證服務 將shangcheng_user_auth工程導入到項目中去&#xff0c;如下圖 啟動eureka&#xff0c;再啟動認證服務 3&#xff09; 認證服務中創建測試類 public class CreateJwtTest { ? /**** 創建令牌測試*/Testpublic voi…

單路由及雙路由端口映射指南

遠程登錄總會遇到登陸不上的情況&#xff0c;可能是訪問的大門沒有打開哦&#xff0c;下面我們來看看具體是怎么回事&#xff1f; 當軟件遠程訪問時&#xff0c;主機需要兩個條件&#xff0c;一是有一個唯一的公網IP地址&#xff08;運營商提供&#xff09;&#xff0c;二是開…

Spring AI 在微服務中的應用:支持分布式 AI 推理

1. 引言 在現代企業中&#xff0c;微服務架構 已成為開發復雜系統的主流方式&#xff0c;而 AI 模型推理 也越來越多地被集成到業務流程中。如何在分布式微服務架構下高效地集成 Spring AI&#xff0c;使多個服務可以協同完成 AI 任務&#xff0c;并支持分布式 AI 推理&#x…

Kafak 單例生產者實現-C#操作

前面寫了一篇入門操作的文章,因為工作需要,簡單修改了下如何實現單例生產者。 Kafka入門-C#操作_c# kafka-CSDN博客文章瀏覽閱讀1.6k次,點贊20次,收藏9次。2).報錯:“kafka.zookeeper.ZooKeeperClientTimeoutException: Timed out waiting for connection while in state…

2024年記 | 凜冬將至

放棄幻想&#xff0c;準備斗爭&#xff01; 考研or就業&#xff1f; 上大學以來&#xff0c;考研上名校在我的心里一直是一顆種子&#xff0c;2024年初&#xff0c;當時的想法是考研和就業兩手抓。買了張宇的高數現代&#xff0c;想要死磕&#xff01; 也記了挺多筆記... 如果…

基于 Jenkins 的測試報告獲取與處理并寫入 Jira Wiki 的技術總結

title: 基于 Jenkins 的測試報告獲取與處理并寫入 Jira Wiki 的技術總結 tags: - jenkins - python categories: - jenkins在軟件開發的持續集成與持續交付&#xff08;CI/CD&#xff09;流程里&#xff0c;及時、準確地獲取并分析測試報告對保障軟件質量至關重要。本文將詳細…

C# 中 default 使用詳解

總目錄 前言 在C#中&#xff0c;default 關鍵字用于表示類型默認值。它可以根據上下文推斷出適用的類型&#xff0c;并返回該類型的默認值。隨著C#版本的發展&#xff0c;default 的用法也變得更加豐富和靈活。本文將詳細介紹 default 在不同場景下的使用方法及其最佳實踐。 一…