使用带有变量参数的函数打印字符串(va_list)

时间:2016-02-29 16:59:44

标签: c string pointers variadic-functions

我正在尝试打印参数变量类型字符串,我一直坚持这个

想法

尝试使用_Str[i] == '\0'作为表达式在while循环中移动,并且EOF返回(-1)定义为'\n' == EOF之后我们在EOF上进行测试返回int main(int argc, char** argv) { ps("test1", "test2"); return 0; } 。而不是切换到下一个变量

代码

的main.c

#ifndef BASE_H_
 #define BASE_H_
  #ifndef EOF // (EOF) - End Of File character. (-1)
   #define EOF (-1)
  #endif// EOF 
 #include<stdio.h>// Facultatif  
 #include<stdarg.h> 

    int ps(const char* , ...); // our function


#endif // BASE_H_

base.h

int ps(const char* _Str, ...)
{
    int  i = 0;

    //char* string;
    //va_list
    //
        va_list arg;
        va_start(arg, _Str);

    //for(i = 0;    ; ++i)
    //  if(_Str[i] == '\0')
    //      putchar('\n');
    while(1)
    {
        while(_Str[i])
        {
            if( putchar(_Str[i]) == EOF)  //test on EOF value
            { 
                return EOF;// (-1)
            }//end if
         i++;
        }//end inner while
           if(putchar('\n') == EOF)  //occur right after we quit due to '\0'
           {
               return EOF;// (-1)
           }//end if
           string = va_arg(arg, char*);
    }//end outter while

        va_end(arg); 
        //
        return 1; //to meet spec.
}// end ps()
//
//

base.c

[ar.lnx@host print] $ make
Building objects..
gcc -c -o main.o main.c -I. -Wall 
Building objects..
gcc -c -o base.o base.c -I. -Wall 
Building the application core..
gcc -o x main.o base.o  -I. -g
Finish.
[ar.lnx@host print] $ ./x
Segmentation fault (core dumped)
[ar.lnx@host print] $ 

使用GCC

进行编译
  // in your PauseButtonView
  let object:[String:AnyObject] = [ "aParameter" : 42 ]
  let startNotification = NSNotification(name: "startFunction:", object: object) 
  NSNotificationCenter.defaultCenter().postNotification(startNotification)

  // in the view controller
  func startFunction(notification:NSNotification)
  {
     let object = notification.object as? [String:AnyObject]
     //...
  }

我坚持这个并且不知道该怎么做,任何人都可以帮助我理解问题并解决它吗?

2 个答案:

答案 0 :(得分:3)

正如mfro已经说过:你必须为你的功能找到一种方法来停止打印。此刻,您很高兴地超越了可变数组的范围。当putchar返回EOF时,您可以离开内部无限循环的唯一方法。可能会发生这种情况,但不太可能发生; putchar仅在失败时返回EOF;输出流没有结束,只要程序将数据注入其中,它就会运行。

(这与输入不同,输入在读取文件末尾或用户键入 Ctrl-D 时结束。例如,getcharEOF是一种通常迟早会发生的情况。输出的情况并非如此。)

如果要实现可变参数函数,基本上有两种可能:前置计数:

ps(3, "Salut", "mon", "ami");

附加一个标记值,通常是NULL

ps("C'est", "la", "vie", NULL);

例如,哨兵变体:

void ps(const char *str, ...)
{
    va_list arg;

    va_start(arg, str);

    while (str) {
        puts(str);
        str = va_arg(arg, const char *);
    }

    va_end(arg);
}

当然,您有可能忘记将哨兵放在最后(或者,如果您选择了计数变体,则忘记更新计数)。使用GCC的function attributes,您可以让编译器在没有哨兵时发出警告。这样做会更好,但仍然很难看,因为在函数调用结束时会有额外的信息。

如果将实现包装在可变参数宏中,则可以静默附加sentinel:

#define ps(...) ps(__VA_ARGS__, NULL)

ps将使用哨兵调用函数ps。 (对于宏和函数使用不同的名称可能是个好主意。在这种情况下,通常会调用宏。)

还存在类型安全问题。没有人会阻止你像这样调用你的函数:

ps(1, 2, 3);

因为可变参数可以是任何类型。 (printf函数依赖于格式良好的格式字符串来查找所有参数的正确类型。)

因为我们已经输入了宏区域,所以你可以使用复合文字来创建一个NULL - 终止的字符串数组:

#define ps(...) print_strings((const char *[]){__VA_ARGS__, NULL})

使用直接函数打印所有字符串:

void print_strings(const char *str[])
{
    while (*str) puts(*str++);
}

这至少会给你关于传递非char指针的警告。

答案 1 :(得分:1)

有两种可能的解决方案。你要么争论参数列表的结尾:

#include <stdio.h>
#include <stdarg.h>

#define END_OF_LIST NULL

int ps1( const char* firstStr, ... )
{
    va_list argptr;
    va_start( argptr, firstStr );

    const char* str = firstStr;
    while ( str != END_OF_LIST ) // terminate if end of argument list
    {
        printf( "%s\n", str );
        str = va_arg( argptr, const char* );
    }
    va_end( argptr );
    return 1;
}

int test_C (void)
{
    ps1( "test1", "test2", NULL );
                        // ^^^^ marke end of argument list
    return 0;
}

或者你传递函数的参数数量:

int ps2( int count, ... )
{
    va_list argptr;
    va_start( argptr, count );

    for( int i = 0; i < count; i++ ) // do "count" times
    {
        const char *str = va_arg( argptr, const char* );
        printf( "%s\n", str );
    }
    va_end( argptr );
    return 1;
}

int main (void)
{
    ps2( 2, "test1", "test2" );
    //   ^ number of arguments
    return 0;
}

最后功能psputchar

#define EOF -1

int ps( const char* firstStr, ... )
{
    va_list argptr;
    va_start( argptr, firstStr );

    const char* str = firstStr;
    while ( str != END_OF_LIST )
    {
        int i = 0;
        while ( str[i] )
        {
            if( putchar( str[i]) == EOF )
                return EOF;
            i++;
        }
        if ( putchar( '\n' ) == EOF )
            return EOF;

        printf( "%s\n", str );
        str = va_arg( argptr, const char* );
    }
    va_end( argptr );
    return 1;
}