可變參數函數(二)

函數樣例:

#include<stdio.h>
#include<stdlib.h>
#include<stdarg.h>double add(int n,...)
{int i = 0;double sum = 0;va_list argptr;va_start(argptr,n);for(i = 0 ; i < n; i++){double d =  va_arg(argptr,double);printf("%d argument is %.3f\n",i,d);  //獲取第i個double型的可變參數sum += va_arg(argptr,double);        }va_end(argptr);    return sum;
}int main(int argc,char **argv)
{double sum = 0;float *p = malloc(argc * sizeof(float));int i;for(i = 1; i < argc; i++)        {        p[i] = atof(argv[i]);    //printf("p[%d] = %.3f\n",i,p[i]);
    }sum = add(1,p[1]);    printf("sum = %.3f\n",sum);sum = add(2,p[1],p[2]);    printf("sum = %.3f\n",sum);sum = add(3,p[1],p[2],p[3]);    printf("sum = %.3f\n",sum);free(p);return 0;
}

運行結果:

exbot@ubuntu:~/wangqinghe/DeBug/20190702$ gcc sum.c -o sum

exbot@ubuntu:~/wangqinghe/DeBug/20190702$ ./sum 10 20 30

0 argument is 10.000

sum = 0.000

0 argument is 10.000

1 argument is 0.000

sum = 20.000

0 argument is 10.000

1 argument is 30.000

2 argument is 0.000

sum = 20.000

?

測試:double d =? va_arg(argptr,double);是否只提取可變參數列表中double類型的數據

#include<stdio.h>
#include<stdlib.h>
#include<stdarg.h>double add(int n,...)
{int i = 0;double sum = 0;va_list argptr;va_start(argptr,n);for(i = 0 ; i < n; i++){double d =  va_arg(argptr,double);printf("%d argument is %.3f\n",i,d);sum += va_arg(argptr,double);        }va_end(argptr);    return sum;
}int main(int argc,char **argv)
{double sum = 0;float *p = malloc(argc * sizeof(float));int i;for(i = 1; i < argc; i++)        {    if(0 == i % 2)    {p[i] = atof(argv[i]);printf("float : p[%d] = %.3f\n",i,p[i]); }}sum = add(1,p[1]);    printf("sum = %.3f\n",sum);sum = add(2,p[1],p[2]);    printf("sum = %.3f\n",sum);sum = add(3,p[1],p[2],p[3]);    printf("sum = %.3f\n",sum);free(p);return 0;
}

運行結果:

exbot@ubuntu:~/wangqinghe/DeBug/20190702$ ./sum 10 20 30 40 50 60 70

float : p[2] = 20.000

float : p[4] = 40.000

float : p[6] = 60.000

0 argument is 0.000

sum = 0.000

0 argument is 0.000

1 argument is 0.000

sum = 20.000

0 argument is 0.000

1 argument is 0.000

2 argument is 0.000

sum = 20.000

結論:可變參數的輸入類型要和使用的一致。(暫定)。


函數介紹:

va_list

這是一個適用于 va_start()、va_arg() 和 va_end() 這三個宏存儲信息的類型。

一般情況下va_list所定義變量為字符指針,即typedef char *va_list

該類型的變量用于存儲參數的地址。因為得到參數的地址之后,再結合參數的類型,才能得到參數的值。

?

va_start

宏原型是:

void va_start(va_list ap, last_arg)

參數:

ap是一個 va_list 類型的對象,它用來存儲通過 va_arg 獲取額外參數時所必需的信息。

last_arg是最后一個傳遞給函數的已知的固定參數。?

該宏與 va_arg 和 va_end 宏是一起使用的,且必須在使用 va_arg 和 va_end 之前被調用。

?

va_arg

宏原型是:

type va_arg(va_list ap, type) 

其作用是從ap開始取一個type型的值返回,并且自動將ap指向下一個參數。所以如果參數類型寫錯了,例如將char*寫成char了,本來要取4個字節,結果只取了一個字節,ap本來要向后面移動4個字節,結果只移動了一個字節,后面的數據就全錯了。

參數:

ap是一個 va_list 類型的對象,存儲了有關額外參數和檢索狀態的信息。該對象應在第一次調用 va_arg 之前通過調用 va_start 進行初始化。

type這是一個類型名稱。該類型名稱是作為擴展自該宏的表達式的類型來使用的。?

返回值:該宏返回下一個額外的參數,是一個類型為 type 的表達式。

?

注意:

va_arg宏的第2個參數不能被指定為char、short或者float類型。

因為char和short類型的參數會被轉換為int類型,而float類型的參數會被轉換為double類型。如果錯誤的指定了,將會在程序中引起麻煩。

例如,這樣寫肯定是不對的:

c = va_arg(ap,char);

因為我們無法傳遞一個char類型參數,如果傳遞了,它將會被自動轉化為int類型。上面的式子應該寫成:

c = va_arg(ap,int);

va_end

宏原型為:

 void va_end(va_list ap) 

參數:

ap是之前由同一函數中的 va_start 初始化的 va_list 對象。?

其作用是作用是將ap設置為NULL,如果在從函數返回之前沒有調用 va_end,則結果為未定義。

?

總結

使用可變長參數的步驟:

?

1.聲明va_list變量;

2.使用va_start指定可變長參數的位置;

3.使用va_arg來獲取參數值;

4.可選,使用va_end將va_list清零。

?

參考原文:https://blog.csdn.net/hmxz2nn/article/details/80445770

?

轉載于:https://www.cnblogs.com/wanghao-boke/p/11121054.html

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

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

相關文章

Linux 內核網絡協議棧 ------sk_buff 結構體 以及 完全解釋 (2.6.16)

在2.6.24之后這個結構體有了較大的變化&#xff0c;此處先說一說2.6.16版本的sk_buff&#xff0c;以及解釋一些問題。一、先直觀的看一下這個結構體~~~~~~~~~~~~~~~~~~~~~~在下面解釋每個字段的意義~~~~~~~~~~~[cpp] view plaincopyprint?struct sk_buff { /* These…

可變參數輸出(三)

Linux C關于輸出函數的定義&#xff1a; int printf(const char *format,…); int vprintf(const char * format,va_list ap); int vfprintf(FILE *stream,cosnt char *format,va_list ap); int vsprintf(char *str,const char *format,va_list ap); int vsnprintf(char *str,s…

最常用的設計模式---適配器模式(C++實現)

適配器模式屬于結構型的設計模式&#xff0c;它是結構型設計模式之首&#xff08;用的最多的結構型設計模式&#xff09;。 適配器設計模式也并不復雜&#xff0c;適配器它是主要作用是將一個類的接口轉換成客戶希望的另外一個接口這樣使得原本由于接口不兼容而不能一起工作的那…

Linux 簡單打印日志(二)

#include<stdio.h> #include<stdlib.h> #include<string.h> #include<time.h> //#include<windows.h> #include <unistd.h> // linux下頭文件#define FILE_MAX_SIZE (1024*1024)void get_local_time(char* buffer){time_t rawtime;struct …

程序隨筆——C++實現的一個線程池

1.線程池簡介 我們知道在線程池是一種多線程處理形式&#xff0c;處理過程中我們將相應的任務提交給線程池&#xff0c;線程池會分配對應的工作線程執行任務或存放在任務隊列中&#xff0c;等待執行。 面向對象編程中&#xff0c;創建和銷毀對象是需要消耗一定時間的&#xff0…

線程池原理及創建并C++實現

本文給出了一個通用的線程池框架&#xff0c;該框架將與線程執行相關的任務進行了高層次的抽象&#xff0c;使之與具體的執行任務無關。另外該線程池具有動態伸縮性&#xff0c;它能根據執行任務的輕重自動調整線程池中線程的數量。文章的最后&#xff0c;我們給出一個簡單示例…

Linux 打印簡單日志(一)

簡單日志輸出&#xff1a; #include<stdio.h> #include<string.h> #include<stdlib.h>void write(char* filename,char* szStr){FILE* fp;fp fopen(filename,"at");if(fp ! NULL){fwrite(szStr,256,1,fp); //fclose(fp);fp NULL;} }int main(int…

c++簡單線程池實現

線程池&#xff0c;簡單來說就是有一堆已經創建好的線程&#xff08;最大數目一定&#xff09;&#xff0c;初始時他們都處于空閑狀態&#xff0c;當有新的任務進來&#xff0c;從線程池中取出一個空閑的線程處理任務&#xff0c;然后當任務處理完成之后&#xff0c;該線程被重…

Linux 打印可變參數日志

實現了傳輸進去的字符串所在的文檔&#xff0c;函數和行數顯示功能。 實現了將傳入的可變參數打印到日志功能。 #include<stdio.h> #include<stdarg.h> #include<string.h>const char * g_path "/home/exbot/wangqinghe/log.txt"; #define LOG(fm…

C++強化之路之線程池開發整體框架(二)

一.線程池開發框架 我所開發的線程池由以下幾部分組成&#xff1a; 1.工作中的線程。也就是線程池中的線程&#xff0c;主要是執行分發來的task。 2.管理線程池的監督線程。這個線程的創建獨立于線程池的創建&#xff0c;按照既定的管理方法進行管理線程池中的所有線程&#xf…

vfprintf()函數

函數聲明&#xff1a;int vfprintf(FILE *stream, const char *format, va_list arg) 函數參數&#xff1a; stream—這是指向了FILE對象的指針&#xff0c;該FILE對象標識了流。 format—c語言字符串&#xff0c;包含了要被寫入到流stream中的文本。它可以包含嵌入的format標簽…

Makefile(二)

將生產的.o文件放進指定的文件中&#xff08;先創建該文件夾&#xff09; src $(wildcard ./*.cpp) obj $(patsubst %.cpp,./output/%.o,$(src))target test$(target) : $(obj)g $(obj) -o $(target) %.o: %.cppg -c $< -o output/$.PHONY:clean clean:rm -f $(target) $…

TCP粘包問題分析和解決(全)

TCP通信粘包問題分析和解決&#xff08;全&#xff09;在socket網絡程序中&#xff0c;TCP和UDP分別是面向連接和非面向連接的。因此TCP的socket編程&#xff0c;收發兩端&#xff08;客戶端和服務器端&#xff09;都要有成對的socket&#xff0c;因此&#xff0c;發送端為了將…

UML類圖符號 各種關系說明以及舉例

UML中描述對象和類之間相互關系的方式包括&#xff1a;依賴&#xff0c;關聯&#xff0c;聚合&#xff0c;組合&#xff0c;泛化&#xff0c;實現等。表示關系的強弱&#xff1a;組合>聚合>關聯>依賴 相互間關系 聚合是表明對象之間的整體與部分關系的關聯&#xff0c…

尋找數組中第二大數

設置兩個數值來表示最大數和第二大數&#xff0c;在循環比較賦值即可 //找給定數組中第二大的數int get_smax(int *arr,int length) {int max;int smax;if(arr[0] > arr[1]){max arr[0];smax arr[1];}else{max arr[1];smax arr[0];}for(int i 2; i < length; i){if(…

timerfd API使用總結

timerfd 介紹 timerfd 是在Linux內核2.6.25版本中添加的接口&#xff0c;其是Linux為用戶提供的一個定時器接口。這個接口基于文件描述符&#xff0c;所以可以被用于select/poll/epoll的場景。當使用timerfd API創建多個定時器任務并置于poll中進行事件監聽&#xff0c;當沒有可…

#if/#else/#endif

在linux環境下寫c代碼時會嘗試各種方法或調整路徑&#xff0c;需要用到#if #include<stdio.h>int main(){int i; #if 0i 1; #elsei 2; #endifprintf("i %d",i);return 0; } 有時候會調整代碼&#xff0c;但是又不是最終版本的更換某些值&#xff0c;就需要注…

內存分配調用

通過函數給實參分配內存&#xff0c;可以通過二級指針實現 #include<stdio.h> #incldue<stdlib.h>void getheap(int *p) //錯誤的模型 {p malloc(100); }void getheap(int **p) //正確的模型 {*p malloc(100); } int main() {int *p NULL;getheap(&p);free(p…

ESP傳輸模式拆解包流程

一、 ESP簡介ESP&#xff0c;封裝安全載荷協議(Encapsulating SecurityPayloads)&#xff0c;是一種Ipsec協議&#xff0c;用于對IP協議在傳輸過程中進行數據完整性度量、來源認證、加密以及防回放攻擊。可以單獨使用&#xff0c;也可以和AH一起使用。在ESP頭部之前的IPV4…

結構體成員內存對齊

#include<stdio.h> struct A {int A; };int main() {struct A a;printf("%d\n",sizeof(a));return 0; } 運行結果&#xff1a;4 #include<stdio.h> struct A {int a;int b&#xff1b; };int main() {struct A a;printf("%d\n",sizeof(a))…