连接C ansi中的任何内容

时间:2013-08-30 12:58:01

标签: c string concatenation function-pointers void-pointers

我需要创建一个C函数来连接任何类型的数据中的两个并返回作为连接结果的字符串。我在下面完成了这个功能,但它不起作用。有人能帮助我吗?

// void pointer does not store value, is just the address of a memory location
char* concatenate(void* varA, int tamA, void* varB, int tamB)
{
    // char is 1 byte
    char* result;
    char* a,b; // helpers
    result = malloc((tamA+tamB)*sizeof(char)); 

    a = varA; // "a" receives the address pointed to by the pointer varA
    b = varB; // "b" receives the address pointed to by the pointer varB
    *result = *result << tamA + *a;
    *result = *result << tamB + *b;
    result = a;    // let the results point to "a"
    return result; // the result is the pointer "a"
}

3 个答案:

答案 0 :(得分:3)

在C中,即使您的代码是C ++,这也是您所要求的,但您不能这样做。

没有办法从裸void *中找出如何将其转换为字符串。

您必须使用以下方式添加某些表单的类型信息,例如printf()的字符串%d表示十进制整数等等。

我认为这是一个可行的原型:

char * concat_any(const char *format1, const void *data1,
                  const char *format2, const void *data2);

我不是说“最佳”甚至“合适”,但至少可以实现该原型。 format字符串可以是printf() - 样式,或其他任何内容。

请注意,对于C,这也是非常不切实际,因为取void *意味着您需要一个指向数据的指针。如果你想要,例如连接两个数字,你不能这样做:

char *fortytwo = concat_any("%d", 4, "%d", 2);  /* BROKEN CODE */

因为它传递整数而不是void *,这非常难看。你必须这样做:

const int four = 4, two = 2;
const char *fortytwo = concat_any("%d", &four, "%d", &two);

这显然不太方便。

所以,使用varargs会更好,但是你会遇到无法将不同的varargs与不同的非变量参数关联的问题,如下所示:

char * concat_anyv(const char *format1, ...,
                   const char *format2, ...);   /* BROKEN CODE */

那么,如何首先拥有两个格式化字符串,然后信任调用者将这两个参数作为varargs传递?这会给:

char * concat_anyv2(const char *format1, const char *format2, ...);

现在我们正在谈论。这可以简单地实现,甚至:在内部连接两个格式化字符串,并调用vsnprintf()两次:一次计算缓冲区大小,然后分配,并再次调用它。

用法就是这样:

char *fortytwo = concat_anyv2("%d", "%d", 4, 2);

完成。

答案 1 :(得分:1)

如果我理解正确,您要做的是将varAvarB指向的数据一个接一个地复制到新的内存缓冲区中,并返回一个char指针这个缓冲区。您可以使用memcpy函数轻松实现此目的。

char *concatenate(void *varA, int tamA, void *varB, int tamB)
{
    char* result = malloc(tamA + tamB); 

    // copy varA to "result"
    memcpy(result, varA, tamA);
    // copy varB to "result" after varA
    memcpy(result+tamA, varB, tamB);

    return result;
}

请注意,无论数据varAvarB是否保留它都会按原样使用,而不会转换为人类可读的表示形式。

答案 2 :(得分:0)

我在C中使用了两个小字符串函数。第一个是其他人使用 printf 模型进行的改编,正如其他人提到的那样,你必须知道数据类型的内容:

char* str(const char *fmt, ...)
{
  int size;
  char *buff;
  va_list argp1;
  va_list argp2;

  va_start(argp1, fmt);
  va_copy(argp2, argp1);

  //calling vsnprintf with a NULL buffer simply returns what would
  //be the size of the resulting string but does not include space for nul byte
  size = vsnprintf(NULL, 0, fmt, argp1) + 1;  
  va_end(argp1);

  //now actually allocate a buffer of the correct size and then fill it
  buff = calloc(1,size);
  assert(buff != NULL);
  vsnprintf(buff, size, fmt, argp2);
  va_end(argp2);

  return buff;
}

有了这个,我可以 concat 做一个简单的

char *d = str("%s%s%d", s1, s2, 25);

我只需记住释放返回的字符串,因为它已分配内存。

我有一个第二个例程,我用于简单的字符串连接,我可以嵌套在其他调用中,因为它为我做了内部清理:

typedef enum {FREE_NONE, FREE_ONE, FREE_TWO, FREE_BOTH} CONCAT_FREE_FLAG;
char *concat(char *one, char *two, CONCAT_FREE_FLAG f)
{
  int size = strlen(one) + strlen(two) + 1;
  char *buff = calloc(1,size);
  assert(buff != NULL);
  strcpy(buff, one);
  strcat(buff, two);

  if( f == FREE_ONE || f == FREE_BOTH)
    free(one);
  if( f == FREE_TWO || f == FREE_BOTH)
    free(two);
  return buff;
}

这允许我做以下事情:

 char *s = concat(
              concat("Static ",str("%dx%d", x, y), FREE_TWO),
              "Other Static", FREE_ONE);

我有这个的原因是语法糖,所以我可以传递动态分配的字符串,获得一个新的动态分配的字符串,但不必担心清理输入字符串。