Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/flash/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 带有va_arg的字符串分段错误_C_String_Segmentation Fault_Variadic Functions - Fatal编程技术网

C 带有va_arg的字符串分段错误

C 带有va_arg的字符串分段错误,c,string,segmentation-fault,variadic-functions,C,String,Segmentation Fault,Variadic Functions,我正在制作一个类似于printf的函数,它需要接受字符串和参数,如: form(“整数%d,字符串%s”,54,“字符串”) 并生成一个字符串“整数54,字符串”。 我使用的是stdarg.h库,因为我的函数需要根据字符串具有可变数量的参数 问题是我遇到了分段错误。我发现只有当我使用传递给va_arg的字符串(char*)执行strlen或strcpy时才会发生这种情况。这是我的密码: #include <stdio.h> #include <stdlib.h> #inc

我正在制作一个类似于printf的函数,它需要接受字符串和参数,如:

form(“整数%d,字符串%s”,54,“字符串”)

并生成一个字符串
“整数54,字符串”
。 我使用的是
stdarg.h
库,因为我的函数需要根据字符串具有可变数量的参数

问题是我遇到了
分段错误
。我发现只有当我使用传递给
va_arg
的字符串(char*)执行
strlen
strcpy
时才会发生这种情况。这是我的密码:

#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;
}
#包括
#包括
#包括
#包括
字符*格式(字符*格式,…)
{
VAU列表ap;字符符号;int br=0,lasti,memo=0;字符*帮助;
整数整数;浮点浮点;双精度;字符字符;字符*字符串;
va_开始(ap,格式);
char*result=(char*)calloc(100,strlen(格式));
strcpy(结果、格式);
for(int i=0;结果[i];i++)
如果(结果[i]='%')
{   
开关(结果[i+1])
{
案例“d”:{
ints=va_arg(ap,int);
intb,save=ints,dec=1,j;char*p=result+i;
对于(b=0;save;b++){save/=10;dec*=10;}
对于(dec/=10,j=0;dec;j++){p[j]=((ints/dec)%10)+0x30;dec/=10;}
strcpy(结果+i+b,格式+i-memo+2);memo+=b-2;
}中断;
案例“f”:{
浮点数=va_arg(ap,双精度);
}中断;
案例“l”:{
双倍=va_arg(ap,双倍);
}中断;
案例“c”:{
chars=va_arg(ap,int);
结果[i]=字符;
}中断;
案例s:{
strings=va_arg(ap,char*);
strcpy(结果+i+strlen(字符串),格式+i-memo+2);memo+=(strlen(字符串)-2);
}中断;
默认值:printf(“未知类型”。\n”);break;
}
i=0;
}
返回结果;
}
int main()
{
chara[100];
scanf(“%s”,a);
char*s=形式(“treci%s peti”,a);
printf(“%s”,s);
printf(“\n”);
免费的;
返回0;
}
strlen或strcpy导致segfault的唯一方法是字符串不是以null结尾的,但我的字符串是以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;
}
许多问题:

  • strcpy(结果+i+strlen(字符串),格式+i-memo+2)是结果的格式。您需要的是将作为变量参数传递的字符串复制到结果字符串。而且,
    result+i+strlen(strings)
    没有任何意义:你为什么写这个
  • 每次找到格式说明符时,都会出现一个
    i=0
    :为什么?这是分段错误的根本原因。每次找到
    %
    时,循环都会重新启动,并请求一个新的变量参数,但仍无法检索其他变量
  • 您必须有两个不同的索引来解析输入格式和索引结果字符串,因为输出字符串可能具有不同的长度
  • 使用以下命令使其非常简单:

    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;
    }
    
    char*格式(const char*格式,…)
    {
    va_列表va;
    va_开始(va,格式);
    int result=vsnprintf(NUll,0,格式,va);
    //错误检查
    如果(结果<0)
    返回NULL;
    //这里的结果是我们需要分配的字节数(不包括终止符)
    char*string=malloc(结果+1);
    //现在进行实际的格式化
    vsnprintf(字符串,结果+1,格式,va);
    返回字符串;
    }
    

    重要提示:请记住释放返回的字符串。

    请尝试创建一个新的字符串并显示给我们好吗?或者至少向我们展示
    表单的更大部分
    函数?我们真的需要看到变量声明、定义和初始化之类的东西。你为什么不使用例如格式化字符串?您可以让它告诉您所需的确切长度,这样您就可以在需要时为字符串动态分配内存。If还将提供所有标准格式,包括您不处理的格式、字段宽度等。我还没有在课程中学习vsnprintf。
    I=0
    If(result[I]='%')
    结尾处,If(result[I]='%')
    不正确。
    strcpy
    调用看起来可能是可疑的。试试看,例如
    memcpy(结果+i,字符串,strlen(字符串));strcpy(结果+i+strlen(字符串),格式+i+2)I=0
    是问题所在。现在我只是
    case's':{strings=va_arg(ap,char*);strcpy(result+I+strlen(strings),format+I-memo+2);memo+=(strlen(strings)-2);memcpy(result+I,strings,strlen(strings));}break可以工作。
    strcpy(结果+i,字符串)
    应该是
    strcpy(结果+memo,字符串)
    ,这样代码可以用于多个格式说明符。