簡體   English   中英

va_arg的字符串分段錯誤

[英]String segmentation fault with va_arg

我正在做一個類似於printf的函數,它需要一個字符串和參數,例如:

form("Integer %d, String %s", 54, "STRING");

並創建一個字符串"Integer 54, String STRING" 我正在使用stdarg.h庫,因為我的函數需要根據字符串具有可變數量的參數。

問題是我遇到了Segmentation fault 我發現只有在使用傳遞給va_arg的字符串(char *)進行strlenstrcpy時,才會發生這種情況。 這是我的代碼:

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

char* form(char *format, ...)
{
    va_list ap;char sign;int br=0,lasti,memo=0;char* help;
    int ints; float floats; double doubles; char chars; char* strings;
    va_start(ap,format);
    char* result=(char*)calloc(100,strlen(format));
    strcpy(result,format);
    for(int i=0; result[i] ;i++)
        if(result[i]=='%')
        {   
            switch (result[i+1])    
            {
                case 'd': {
                    ints=va_arg(ap,int);
                    int b,save=ints,dec=1,j;char *p=result+i;
                    for(b=0;save;b++) {save/=10;dec*=10;}
                    for(dec/=10,j=0; dec ; j++) { p[j]=((ints/dec)%10)+0x30; dec/=10; }
                    strcpy(result+i+b,format+i-memo+2);memo+=b-2;
                } break;

                case 'f': {
                    floats=va_arg(ap,double);

                } break;

                case 'l': {
                    doubles=va_arg(ap,double);

                } break;

                case 'c': {
                    chars=va_arg(ap,int);
                    result[i]=chars;
                } break;

                case 's': {
                    strings=va_arg(ap,char*);
                    strcpy(result+i+strlen(strings),format+i-memo+2);memo+=(strlen(strings)-2);
                } break;

                default: printf("Unknown type.\n"); break;
            }
            i=0;
        }

    return result;
}

int main()
{
    char a[100];
    scanf("%s",a);
    char*s=form("treci %s peti",a);
    printf("%s", s);

    printf("\n");
    free(s);
    return 0;
}

strlen或strcpy可能導致段錯誤的唯一方法是,如果字符串不是以null結尾的字符串,而是我的字符串。 那么,這里有什么問題,我該如何解決?

編輯:添加代碼。

僅針對%s情況進行了測試

char* form(char *format, ...)
{
    va_list ap;char sign;int br=0,lasti,memo=0;char* help;
    int ints; float floats; double doubles; char chars; char* strings;
    va_start(ap,format);
    char* result=(char*)calloc(100,strlen(format));
//    strcpy(result,format);
    for(int i=0; format[i] ;i++)
    {
        if(format[i]=='%')
        {
            switch (format[i+1])
            {
                case 'd': {
                    ints=va_arg(ap,int);
                    int b,save=ints,dec=1,j;char *p=result+i;
                    for(b=0;save;b++) {save/=10;dec*=10;}
                    for(dec/=10,j=0; dec ; j++) { p[j]=((ints/dec)%10)+0x30; dec/=10; }
                    strcpy(result+i+b,format+i-memo+2);memo+=b-2;
                } break;

                case 'f': {
                    floats=va_arg(ap,double);

                } break;

                case 'l': {
                    doubles=va_arg(ap,double);

                } break;

                case 'c': {
                    chars=va_arg(ap,int);
                    result[i]=chars;
                } break;

                case 's': {
                    strings=va_arg(ap,char*);
                    strcpy(result+memo,strings);
                    memo+=strlen(strings);
                } break;

                default: printf("Unknown type.\n"); break;
            }
            i++;
        }
        else
        {
            result[memo++] = format[i];
        }
    }

    return result;
}

很多問題:

  1. strcpy(result+i+strlen(strings),format+i-memo+2); 是應付的格式。 您需要將作為變量參數傳遞的字符串復制到結果字符串。 此外, result+i+strlen(strings)沒有任何意義:您為什么寫那個?
  2. 每次您找到格式說明符%i=0為什么? 這是分割錯誤的根本原因。 每次找到%並請求新的變量參數時,循環都會重新啟動,但仍然沒有其他變量可以檢索。
  3. 由於輸出字符串可能具有不同的長度,因此您必須具有2個不同的索引來解析輸入格式字符串並為結果字符串建立索引。

使用vsnprintf使其非常簡單:

char *form(const char *format, ...)
{
    va_list va;
    va_start(va, format);

    int result = vsnprintf(NUll, 0, format, va);

    // Error checking
    if (result < 0)
        return NULL;

    // Here result is the number of bytes we need to allocate (excluding terminator)
    char *string = malloc(result + 1);

    // Now do the actual formatting
    vsnprintf(string, result + 1, format, va);

    return string;
}

重要:請記住free返回的字符串。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM