修改C中的字符串

时间:2010-09-06 19:04:58

标签: c string

我需要将以下字符串存储在C:

中的3个char *变量中
[foo]
[foo]:[bar]
[foo]:[bar]:[tat]

通过char *指针在一个时间点接收诸如“foo”的每个单独的字符串,在接收第二个字符串之前立即产生相应的输出字符串,并且始终知道各个字符串的总数。

可以有任意数量的字符串。

我编写了以下代码来打印字符串:

for(i=0;i<num;i++)
    {  
        for(j=0;j<=i;j++)
            {
                printf("[%s]",str[j]);
                if(j!=i)
                {
                    printf(":");
                }
                else
                {
                    printf("\n");
                }
            }       
    }   

但是我无法想出一种在变量中存储所需输出字符串的方法,除了使用strcat()&amp ;;编写一个混乱的逐个案例函数。一些额外的自定义函数。

有没有办法做到这一点,看起来像打印字符串一样干净?

4 个答案:

答案 0 :(得分:3)

这是一个内存管理和字符串处理在C中的繁琐问题。如果我认为对于n个输入字符串,你想要n个输出字符串,每个字符串都比最后一个更长,我会这样做:

char **results = malloc(num * sizeof(char*));
if (results == 0) return ENOMEM;
int lastlen = 0;
for (int i = 0; i < num; ++i) {
    char *newresult = malloc(lastlen + strlen(str[i]) + 4);
    if (newresult == 0) { /* even more tedious freeing code goes here */ }
    results[i] = newresult;
    char *ptr = newresult;
    if (i != 0) {
        ptr += sprintf(ptr, "%s:", results[i-1])
    }
    sprintf(ptr, "[%s]", str[i])
    lastlen = strlen(newresult);
}

或类似的东西。显然,这里有一个很好的机会来编写多个函数,将这些字符串的生成与它们在数组中的存储分开。还有一个通常的论点,即我们如何在缓冲风险溢出风险中做得比sprintf +心算术更好。

编辑:偷走了Oskar使用sprintf

另一个编辑:asprintf的示例,可在GNU和BSD上使用。这包括繁琐的解放代码,成功路径实际上相当不错。成功时返回新分配的数组,出错时返回0。假设调用者知道num,因此知道数组的长度:如果没有用,那么数组可能是空终止的。

char **results = malloc(num * sizeof(char*));
if (results != 0) {
    const char *last = "";
    const char *sep = "";
    for (int i = 0; i < num; ++i) {
        if (asprintf(results + i, "%s%s[%s]", last, sep, str[i]) == -1) break;
        last = str[i];
        sep = ":";
    }
    if (i == num) return results; // success!
    // asprintf failed, so the value of results[i] is undefined
    while (i != 0) free(results[--i]);
    free(results); 
}
return 0;

答案 1 :(得分:1)

您可以使用sprintf()。以您的代码为例:

for(i=0;i<num;i++)
{  
    char s[N];
    s[0] = '\0';
    for(j=0;j<=i;j++)
        {
            sprintf(s+strlen(s),"[%s]",str[j]);
            if(i!=j)
            {
                sprintf(s+strlen(s),":");
            }
            else
            {
                sprintf(s+strlen(s),"\n");
            }
        }      
    /* store 's' somewhere */
}   

编辑:我不建议将此解决方案用于任何严肃的事情。但对于一个简单的应用程序,你只想完成它,它应该完成这项工作。只需要 N 足够大,或动态分配它以保存最大的字符串。

答案 2 :(得分:1)

您有两个不同的问题:确保您分配足够的空间以及创建字符串。 有很多方法可以平衡两者,但使用realloc()可以非常简单。 这是一个检查并在需要时扩大缓冲区的解决方案。

权衡取决于代码复杂性与性能,例如:

  • 计算内存需求并分配一次与在循环中更简单地执行(恕我直言)。
  • 通过过度分配来浪费记忆,经常(重新)分配浪费时间。
  • 使用更简单的strcpy()与简单使用sprintf()

我的版本

char *joinCmds( char* str[], /* The strings to concatenate */
                int num )    /* the number of strings */
{
    int  len = 0, i, off = 0;
    char *out = NULL, sep;

    for(i=0; i<num; i++)
    {
        while (len < (off+4+strlen(str[i]))) {
            len += 16384;      /* Larger numbers wastes memory in for better performance */
            out = realloc( out, len );  /* Warning: some 'realloc()' take 3 parameters */
            /** Handle NULL (Out of Memory errors) */
        }
        sep  = (i < (num-1)) ? ':' : '\n';
        off += sprintf(&out[off], "[%s]%c", str[i], sep);
    }
    return out;
}

答案 3 :(得分:0)

strcpy的解决方案;使用sprintf也很容易。

char out[1000],*p=out; /* out with enough size */
int i=0;
/* num > 0 */
for(; i<num && (p+=strlen(strcpy(p,"]:["))) ; p+=strlen(strcpy(p,str[i++])) ) ;
strcpy(p,"]");
puts(out+2);