Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/60.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 具有自动内存分配功能的sprintf()?_C_Malloc_Printf - Fatal编程技术网

C 具有自动内存分配功能的sprintf()?

C 具有自动内存分配功能的sprintf()?,c,malloc,printf,C,Malloc,Printf,我正在搜索一个函数的类似sprintf()的实现,该函数可以自动分配所需的内存。所以我想说 char* my_str = dynamic_sprintf( "Hello %s, this is a %.*s nice %05d string", a, b, c, d ); my_str检索保存此sprintf()结果的已分配内存的地址 在另一个论坛上,我读到可以这样解决这个问题: #include <stdlib.h> #include <stdio.h> #inclu

我正在搜索一个函数的类似sprintf()的实现,该函数可以自动分配所需的内存。所以我想说

char* my_str = dynamic_sprintf( "Hello %s, this is a %.*s nice %05d string", a, b, c, d );
my_str检索保存此sprintf()结果的已分配内存的地址

在另一个论坛上,我读到可以这样解决这个问题:

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

int main()
{
    char*   ret;
    char*   a = "Hello";
    char*   b = "World";
    int     c = 123;

    int     numbytes;

    numbytes = sprintf( (char*)NULL, "%s %d %s!", a, c, b );
    printf( "numbytes = %d", numbytes );

    ret = (char*)malloc( ( numbytes + 1 ) * sizeof( char ) );
    sprintf( ret, "%s %d %s!", a, c, b );

    printf( "ret = >%s<\n", ret );
    free( ret );

    return 0;
}
#包括
#包括
#包括
int main()
{
char*ret;
char*a=“你好”;
char*b=“世界”;
int c=123;
整数单位;
numbytes=sprintf((char*)NULL,“%s%d%s!”,a,c,b);
printf(“numbytes=%d”,numbytes);
ret=(char*)malloc((numbytes+1)*sizeof(char));
sprintf(ret,“%s%d%s!”,a,c,b);
printf(“ret=>%s
  • 如果可能的话,使用——它提供了一种简单的方法来测量将生成的数据的大小,以便分配空间
  • 如果你真的不能这样做,另一种可能是使用
    fprintf
    打印到一个临时文件,以获得大小,分配内存,然后使用sprintf。
    snprintf
    无疑是首选方法
  • GNU和BSD有和vasprintf,它们的设计目的就是为您这样做。它将为您确定如何分配内存,并且在任何内存分配错误时返回null

    asprintf在分配字符串方面做的是正确的——它首先测量大小,然后尝试使用malloc进行分配。如果失败,它将返回null。除非您有自己的内存分配系统阻止使用malloc,否则asprintf是执行此任务的最佳工具

    代码如下所示:

    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    int main()
    {
        char*   ret;
        char*   a = "Hello";
        char*   b = "World";
        int     c = 123;
    
        ret = asprintf( "%s %d %s!", a, c, b );
        if (ret == NULL) {
            fprintf(stderr, "Error in asprintf\n");
            return 1;
        }
    
        printf( "ret = >%s<\n", ret );
        free( ret );
    
        return 0;
    }
    
    #包括
    #包括
    #包括
    int main()
    {
    char*ret;
    char*a=“你好”;
    char*b=“世界”;
    int c=123;
    ret=asprintf(“%s%d%s!”,a,c,b);
    if(ret==NULL){
    fprintf(stderr,“asprintf中的错误”);
    返回1;
    }
    printf(“ret=>%s如果针对GLib进行链接是一个选项,则库提供的函数完全满足您的需要。从文档中:

    类似于标准C
    sprintf()
    功能,但更安全,因为它 计算所需的最大空间 并分配内存来保存 结果。返回的字符串应为 不再使用时使用
    g_free()
    释放 需要


    这是原始答案。正如其他人提到的,您需要
    snprintf
    而不是
    sprintf
    。确保
    snprintf
    的第二个参数是
    zero
    。这将防止
    snprintf
    写入第一个参数的
    NULL
    字符串

    第二个参数是必需的,因为它告诉
    snprintf
    没有足够的空间写入输出缓冲区。当没有足够的空间时
    snprintf
    返回如果有足够的空间,它将写入的字节数

    从这里的链接复制代码

    char* get_error_message(char const *msg) {
        size_t needed = snprintf(NULL, 0, "%s: %s (%d)", msg, strerror(errno), errno) + 1;
        char  *buffer = malloc(needed);
        sprintf(buffer, "%s: %s (%d)", msg, strerror(errno), errno);
        return buffer;
    }
    

    如果您可以使用GNU/BSD扩展,那么问题已经得到了回答。您可以使用
    asprintf()
    (和
    vasprintf()
    构建包装函数)并完成

    但是根据手册页,POSIX强制使用
    snprintf()
    vsnprintf()
    ,后者可用于构建自己的
    asprintf()
    vasprintf()
    的简单版本

    您可以使用一些预处理器魔法,并仅在不支持这些功能的系统上使用您的函数版本。

    POSIX.1(又名IEEE 1003.1-2008)提供了OpenMemstream:

    /*  casprintf print to allocated or reallocated string
    
    char *aux = NULL;
    casprintf(&aux,"first line\n");
    casprintf(&aux,"seconde line\n");
    printf(aux);
    free(aux);
    */
    int vcasprintf(char **strp,const char *fmt,va_list ap)
    {
      int ret;
      char *strp1;
      char *result;
      if (*strp==NULL)
         return vasprintf(strp,fmt,ap);
    
      ret=vasprintf(&strp1,fmt,ap); // ret = strlen(strp1) or -1
      if (ret == -1 ) return ret;
      if (ret==0) {free(strp1);return strlen(*strp);}
    
      size_t len = strlen(*strp);
      *strp=realloc(*strp,len + ret +1);
      memcpy((*strp)+len,strp1,ret+1);
      free(strp1);
      return(len+ret);
    }
    
    int casprintf(char **strp, const char *fmt, ...)
    {
     int ret;
     va_list ap;
     va_start(ap,fmt);
     ret =vcasprintf(strp,fmt,ap);
     va_end(ap);
     return(ret);
    }
    
    char *ptr;
    size_t size;
    FILE *f = open_memstream(&ptr, &size);
    fprintf(f, "lots of stuff here\n");
    fclose(f);
    write(1, ptr, size); /* for example */
    free(ptr);
    
    open_memstream(3)至少在Linux和macOS上可用,并且已经使用了一些年。open_memstream(3)的相反版本是fmemopen(3),它使缓冲区的内容可用于读取


    如果您只需要一个sprintf(3),那么广泛实现但非标准的asprintf(3)可能就是你想要的。

    给你这个建议的人可能意味着你应该使用
    snprintf
    ,而不是
    sprintf
    。可能是Hello的复制品,谢谢!但这只是glibc,我需要一个平台无关的解决方案。所以也许最好是自己来做?GLib(GTK+的基础),而不是GNU C库(glibc).但它相当于glibc的asprintf.glib是独立于平台的Sprintf()这将是我选择的功能-但不幸的是,它不标准且不可移植-不好!@theshamen-你要求的定义是非标准且不可移植的。获取
    asprintf
    的源代码,如果需要,将其拉入你的项目中,或者独立地重新实现它。我没有听说过
    asprintf()
    返回指针。GNU和BSD附带的指针(由gnulib和libstrl提供)与等价的
    printf()调用具有相同的返回值,并将指向指针的指针作为第一个参数。因此,
    char*s;int ret=asprintf(&s,“%s%d%s!”,a,c,b)
    ret==-1
    上出现错误。只是想知道,哪些系统/库提供了一个
    asprintf()
    ,它返回的指针与此答案类似?您只能将
    va_list
    变量传递给一个函数。要使用
    vsnprintf()
    两次,您应该使用
    vasprrintf()
    。如果您在从
    vasprintf()
    返回之前添加
    va_end(ap1)
    (例如,在调用
    vsnprintf()
    之后)。您忘记在vasprintf的末尾设置strp,代码中有一些错误处理(它处理
    calloc
    的故障)但是如果
    vsnprintf
    失败,它仍然会爆炸:如果小于-1作为第一个
    vsnprintf
    的错误代码返回,那么大小计算就会结束。如果
    vsnprintf
    的第二次调用失败,缓冲区就会泄漏。您不应该在
    需要的
    中添加1来解释终止的空字符吗?起初没有在第一行的末尾发现+1(它在可见区域之外)
    
    char *ptr;
    size_t size;
    FILE *f = open_memstream(&ptr, &size);
    fprintf(f, "lots of stuff here\n");
    fclose(f);
    write(1, ptr, size); /* for example */
    free(ptr);