0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

C語言-函數(shù)的可變形參(不定形參)

DS小龍哥-嵌入式技術(shù) ? 來源:DS小龍哥-嵌入式技術(shù) ? 作者:DS小龍哥-嵌入式技 ? 2022-08-14 09:58 ? 次閱讀

1. 前言

在學(xué)習(xí)C語言函數(shù)章節(jié)時(shí)發(fā)現(xiàn),給函數(shù)傳入的形參必須和函數(shù)定義原型的類型、數(shù)量一致才可以正常調(diào)用。

平時(shí)使用的printf,scanf等函數(shù)時(shí),傳入的參數(shù)數(shù)量卻可以隨意改變,例如:

printf("大家好");
printf("我是整數(shù):%d\n",123);
printf("%d%d%d%d\n",1,2,3,4);
printf("%s%s%s\n","1","2","3","4");

printf函數(shù)是如何實(shí)現(xiàn)這種傳參方式的?

我們看一下printf,scanf系列函數(shù)的原型。

#include 
int printf(const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
int sprintf(char *str, const char *format, ...);
int snprintf(char *str, size_t size, const char *format, ...);

#include 
int scanf(const char *format, ...);
int fscanf(FILE *stream, const char *format, ...);
int sscanf(const char *str, const char *format, ...);

發(fā)現(xiàn)這些函數(shù)定義時(shí),參數(shù)列表里有一個(gè)省略符號...,這個(gè)省略符號就表示當(dāng)前函數(shù)支持不定長形參。

示例代碼:可變形參的聲明方式

#include 
#include 
#include 
void func(char *p,...);
int main(int argc,char **argv)
{
	func("123",1,2,3,4,"",12.345);
	return 0;
}

//正確的
void func(char *p,...)
{
	
}

//錯(cuò)誤的
void func2(...,char *p)
{
	
}

//錯(cuò)誤的
void func3(...)
{
	
}

2. 可變形參本身實(shí)現(xiàn)原理

明白了如何定義可變形參,接下來就得學(xué)習(xí)可變形參的原理,然后學(xué)習(xí)如何去提取這些傳入的參數(shù)。

(1). 函數(shù)的形參是放在棧空間的。

(2). 可變形參,傳入的多余的參數(shù)都是存放在??臻g。

存放內(nèi)存地址是連續(xù)的。

理論上只要知道傳入?yún)?shù)的首地址,就可以推出其他參數(shù)的地址。

系統(tǒng)的標(biāo)準(zhǔn)參數(shù)頭文件和處理可變形參的相關(guān)函數(shù)

#include 
int vprintf(const char *format, va_list ap);
int vfprintf(FILE *stream, const char *format, va_list ap);
int vsprintf(char *str, const char *format, va_list ap);
int vsnprintf(char  *str,  size_t  size,  const  char  *format,va_list ap);

直接查看頭文件的幫助:
[wbyq@wbyq linux_c]$ man stdarg.h
void va_start(va_list ap, argN);   //開始
void va_copy(va_list dest, va_list src); //拷貝
type va_arg(va_list ap, type);  //取具體形參—取值
void va_end(va_list ap);  //結(jié)束

va_list ap; 就是定義一個(gè)char類型的指針。va_list==char *

3. 單獨(dú)提取參數(shù)列表里的值

#include 
#include 
#include 
#include 

void foo(char *fmt, ...);
int main(int argc,char **argv)
{
	foo("%d,%s,%c",12,"123",'A');
	return 0;
}

// foo("%d,%s,%c",12,"123",'A')
void foo(char *fmt, ...)
{
   va_list ap;  //定義一個(gè)char類型指針
   int d;
   char c, *s;

   va_start(ap, fmt); //指針地址賦值--初始化
   while (*fmt)
	   switch (*fmt++) {
	   case 's':              /* string */
		   s = va_arg(ap, char *);
		   printf("string %s\n", s);
		   break;
	   case 'd':              /* int */
		   d = va_arg(ap, int);
		   printf("int %d\n", d);
		   break;
	   case 'c':              /* char */
		   c = (char) va_arg(ap, int);
		   printf("char %c\n", c);
		   break;
	   }
   va_end(ap); //將ap指針置為NULL
}

4. 使用格式化方式提取形參列表里的值

#include 
#include 
#include 
#include 

void foo(char *fmt, ...);
int main(int argc,char **argv)
{
	foo("int=%d,string=%s char=%c",12,"123",'A');
	return 0;
}

// foo("%d,%s,%c",12,"123",'A')
void foo(char *fmt, ...)
{
   char buff[100];
   va_list ap;  //定義一個(gè)char類型指針
   va_start(ap, fmt); //指針地址賦值--初始化
   //將參數(shù)列表里所有參數(shù),按照格式化轉(zhuǎn)換成字符串-存放到str指向的空間
   vsprintf(buff,fmt,ap);
   va_end(ap); //將ap指針置為NULL
   
   printf("%s\n",buff);
}

5. 提取可變形參列表里的單個(gè)數(shù)據(jù)

#include 
#include 
#include 
#include 

void foo(char *fmt, ...);
int main(int argc,char **argv)
{
	foo("sdcf","hello",666,'A',123.456);
	return 0;
}

void foo(char *fmt, ...)
{
   va_list ap;  //定義一個(gè)char類型指針
   int d;
   char c, *s;
   double f;
   
   va_start(ap, fmt); //指針地址賦值--初始化
   while(*fmt) //遍歷fmt指針指向空間的值
   {
		 switch(*fmt++) 
		{
			case 's':              /* string */
			   s = va_arg(ap, char *);
			   printf("字符串:%s\n", s);
			   break;
			case 'd':              /* int */
			   d = va_arg(ap, int);
			   printf("整型:%d\n", d);
			   break;
			case 'c':              /* char */
			   c = (char) va_arg(ap,int);
			   printf("字符:%c\n", c);
			   break;
			case 'f':              /* float */
			   f = va_arg(ap, double);
			   printf("浮點(diǎn)數(shù):%f\n", f);
			   break;
		}
   }
   va_end(ap); //將ap指針置為NULL
}

6. 精簡代碼-提取可變形參列表里的單個(gè)數(shù)據(jù)

#include 
#include 
#include 
#include 

void foo(char *fmt, ...);
int main(int argc,char **argv)
{
	foo("123","hello",666,'A',123.456);
	return 0;
}

void foo(char *fmt, ...)
{
   va_list ap;  //定義一個(gè)char類型指針
   va_start(ap, fmt); //指針地址賦值--初始化
   printf("第一個(gè)字符串:%s\n",fmt);
   printf("提取字符串:%s\n",va_arg(ap,char*));
   printf("提取整數(shù):%d\n",va_arg(ap,int));
   printf("提取字符:%c\n",va_arg(ap,int));
   printf("提取字符:%lf\n",va_arg(ap,double));
   va_end(ap); //將ap指針置為NULL
}
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • C語言
    +關(guān)注

    關(guān)注

    180

    文章

    7575

    瀏覽量

    134124
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4237

    瀏覽量

    61969
收藏 人收藏

    評論

    相關(guān)推薦

    C語言可變形是什么

    ??C語言允許定義參數(shù)數(shù)量可變函數(shù),這稱為可變參數(shù)函數(shù)(variadic function)。
    的頭像 發(fā)表于 08-18 21:40 ?1240次閱讀

    函數(shù)的實(shí)參與形

    函數(shù)定義中指定的形,在未發(fā)生函數(shù)調(diào)用時(shí)不占內(nèi)存,只有函數(shù)調(diào)用時(shí),函數(shù)中的形
    發(fā)表于 10-18 20:15

    單片機(jī)函數(shù)被改變的原因是什么?

    單片機(jī)函數(shù)被改變的原因是什么?
    發(fā)表于 10-19 07:03

    一種飛記錄數(shù)據(jù)解析軟件的設(shè)計(jì)與實(shí)現(xiàn)

    統(tǒng)的工作情況和各種飛行狀態(tài)的信息。一旦浮空器發(fā)生飛行故障,飛記錄數(shù)據(jù)為查找設(shè)備故障及失事原因提供重要依據(jù)。飛記錄數(shù)據(jù)解析軟件根據(jù)約定的傳輸協(xié)議,將特定形式的記錄數(shù)據(jù)解析為便于查看的記錄數(shù)據(jù),其解析的效率直
    發(fā)表于 11-11 17:29 ?5次下載
    一種飛<b class='flag-5'>參</b>記錄數(shù)據(jù)解析軟件的設(shè)計(jì)與實(shí)現(xiàn)

    C++語言入門教程之C++語言程序設(shè)計(jì)函數(shù)的詳細(xì)資料概述免費(fèi)下載

    本文檔的主要內(nèi)容詳細(xì)介紹的是C++語言入門教程之C++語言程序設(shè)計(jì)函數(shù)的詳細(xì)資料概述免費(fèi)下載內(nèi)容包括了:1
    發(fā)表于 09-20 14:51 ?23次下載

    C語言函數(shù)不改變形內(nèi)容的說明

    注:本文是作者以前發(fā)表在其個(gè)人博客,現(xiàn)在發(fā)布到“聚豐開發(fā)”專欄這也是面試時(shí)常碰到的題,通常是把一個(gè)指針作為函數(shù)的輸入?yún)?shù),在函數(shù)內(nèi)部會改變輸入?yún)?shù)對應(yīng)的指針,問面試者在函數(shù)調(diào)用過程中指針的具體內(nèi)容
    的頭像 發(fā)表于 10-29 11:01 ?4851次閱讀

    C語言總結(jié)_數(shù)組與函數(shù)練習(xí)題

    字符串標(biāo)準(zhǔn)處理函數(shù)介紹(string.h)、指針和數(shù)組當(dāng)做函數(shù),指針定義、函數(shù)返回指針、void類型定義指針、類型強(qiáng)制轉(zhuǎn)換、常量聲明、extern外邊引用聲明關(guān)鍵字。
    的頭像 發(fā)表于 08-14 09:36 ?737次閱讀

    C語言-函數(shù)的定義、聲明、傳

    C語言函數(shù)是非常重要的知識點(diǎn),一個(gè)完整的C語言程序就是由主函數(shù)和各個(gè)子
    的頭像 發(fā)表于 08-14 09:57 ?1802次閱讀

    C語言-指針作為函數(shù)類型

    C語言函數(shù)里最常用就是指針傳和返回地址,特別是字符串處理中,經(jīng)常需要封裝各種功能函數(shù)完成數(shù)據(jù)處理。
    的頭像 發(fā)表于 08-14 10:05 ?1689次閱讀

    數(shù)組/指針的傳問題

    自定義函數(shù)里形的類型,要和函數(shù)調(diào)用中傳過去的實(shí)參類型相對應(yīng)
    的頭像 發(fā)表于 08-17 10:37 ?1010次閱讀

    關(guān)于征集《信息安全技術(shù) 散列函數(shù)》系列國家標(biāo)準(zhǔn)編單位的通知

    關(guān)于征集《信息安全技術(shù) 散列函數(shù) 第1部分 概述》標(biāo)準(zhǔn)編單位的通知 關(guān)于征集《信息安全技術(shù) 散列函數(shù) 第2部分 采用n位塊密碼的散列函數(shù)》標(biāo)準(zhǔn)
    的頭像 發(fā)表于 11-15 14:39 ?609次閱讀

    C語言函數(shù)調(diào)用的形式及過程

    C語言函數(shù)調(diào)用時(shí)的數(shù)據(jù)傳遞 在調(diào)用有函數(shù)時(shí),主調(diào)函數(shù)和被調(diào)
    的頭像 發(fā)表于 03-10 14:28 ?1488次閱讀

    C語言函數(shù)參數(shù)介紹

    C語言數(shù)組元素作函數(shù)實(shí)參 數(shù)組元素可以用作函數(shù)實(shí)參,不能用作形。 C
    的頭像 發(fā)表于 03-10 14:30 ?2145次閱讀

    如何實(shí)現(xiàn)一個(gè)自己的printf函數(shù)代碼?

    C語言中,可變參數(shù)函數(shù)可變參數(shù)宏都允許函數(shù)或宏接受不定
    發(fā)表于 09-06 14:20 ?786次閱讀
    如何實(shí)現(xiàn)一個(gè)自己的printf<b class='flag-5'>函數(shù)</b>代碼?

    Python函數(shù)的分類

    的分類 形的分類可以分為六種: 帶有默認(rèn)值的位置形 不帶默認(rèn)值的位置形 帶有默認(rèn)值的關(guān)鍵字形 不帶默認(rèn)值的關(guān)鍵字形
    的頭像 發(fā)表于 11-14 11:19 ?670次閱讀