c - C中的动态字符串连接

标签 c concatenation

我知道这是一个很常见的问题,但我想知道您对以下功能的看法。这个想法是这个函数可以连接字符串而不用担心结果大小:

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

#define TAM 15 

char* concat(char* answer, char* src, unsigned int* limit, unsigned int* total)
{
 unsigned int length = strlen(src);

 if((*limit - *total) > length)
  strcat(answer, src); 
 else
 {
  *limit *= 2;
  answer = realloc(answer, sizeof(char)*(*limit));
  printf("RESIZING...\n");
  if(answer == NULL)
  {  
   printf("RESIZING ERROR...\n"); 
   return NULL;
  }

  strcat(answer, src); 
 }

 *total += length;

 return answer;
}

int main(void)
{
 char* strings[] = { "ONE", "TWO", "THREE", "FOUR", "FIVE" };

 unsigned int LIMIT = TAM;   //<------
 unsigned int total = 0;     //<------

 char* mem_block = calloc(LIMIT, sizeof(char));

 unsigned int i;
 for(i = 0; i<5; ++i)
  mem_block = concat(mem_block, strings[i], &LIMIT, &total);  //<------

 printf("RES : %s -- %d\n", mem_block, strlen(mem_block));

 free(mem_block);

 return 0;  
}

这个例子运行良好并且 valgrind 报告一切正常:

elias@elias-VirtualBox ~/Desktop $ valgrind ./reSize2
==2939== Memcheck, a memory error detector
==2939== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==2939== Using Valgrind-3.6.1-Debian and LibVEX; rerun with -h for copyright info
==2939== Command: ./reSize2
==2939== 
RESIZING...
RES : ONETWOTHREEFOURFIVE -- 19
==2939== 
==2939== HEAP SUMMARY:
==2939==     in use at exit: 0 bytes in 0 blocks
==2939==   total heap usage: 2 allocs, 2 frees, 45 bytes allocated
==2939== 
==2939== All heap blocks were freed -- no leaks are possible
==2939== 
==2939== For counts of detected and suppressed errors, rerun with: -v
==2939== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 11 from 6)

但有几件事我不喜欢。我不喜欢必须将此变量//<---- 传递给函数。有更好的方法吗?而且,如果我没有收到返回指针“mem_block”,valgrind 会输出以下内容:

==2923== Memcheck, a memory error detector
==2923== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==2923== Using Valgrind-3.6.1-Debian and LibVEX; rerun with -h for copyright info
==2923== Command: ./reSize2
==2923== 
RESIZING...
==2923== Invalid read of size 1
==2923==    at 0x4028D51: strcat (mc_replace_strmem.c:176)
==2923==    by 0x8048523: concat (in /home/elias/Desktop/reSize2)
==2923==    by 0x8048624: main (in /home/elias/Desktop/reSize2)
==2923==  Address 0x41ca028 is 0 bytes inside a block of size 15 free'd
==2923==    at 0x402896C: realloc (vg_replace_malloc.c:525)
==2923==    by 0x8048546: concat (in /home/elias/Desktop/reSize2)
==2923==    by 0x8048624: main (in /home/elias/Desktop/reSize2)
==2923== 
==2923== Invalid read of size 1
==2923==    at 0x4028D59: strcat (mc_replace_strmem.c:176)
==2923==    by 0x8048523: concat (in /home/elias/Desktop/reSize2)
==2923==    by 0x8048624: main (in /home/elias/Desktop/reSize2)
==2923==  Address 0x41ca029 is 1 bytes inside a block of size 15 free'd
==2923==    at 0x402896C: realloc (vg_replace_malloc.c:525)
==2923==    by 0x8048546: concat (in /home/elias/Desktop/reSize2)
==2923==    by 0x8048624: main (in /home/elias/Desktop/reSize2)
==2923== 
==2923== Invalid write of size 1
==2923==    at 0x4028D6F: strcat (mc_replace_strmem.c:176)
==2923==    by 0x8048523: concat (in /home/elias/Desktop/reSize2)
==2923==    by 0x8048624: main (in /home/elias/Desktop/reSize2)
==2923==  Address 0x41ca033 is 11 bytes inside a block of size 15 free'd
==2923==    at 0x402896C: realloc (vg_replace_malloc.c:525)
==2923==    by 0x8048546: concat (in /home/elias/Desktop/reSize2)
==2923==    by 0x8048624: main (in /home/elias/Desktop/reSize2)
==2923== 
==2923== Invalid write of size 1
==2923==    at 0x4028D7C: strcat (mc_replace_strmem.c:176)
==2923==    by 0x8048523: concat (in /home/elias/Desktop/reSize2)
==2923==    by 0x8048624: main (in /home/elias/Desktop/reSize2)
==2923==  Address 0x41ca035 is 13 bytes inside a block of size 15 free'd
==2923==    at 0x402896C: realloc (vg_replace_malloc.c:525)
==2923==    by 0x8048546: concat (in /home/elias/Desktop/reSize2)
==2923==    by 0x8048624: main (in /home/elias/Desktop/reSize2)
==2923== 
==2923== Invalid write of size 1
==2923==    at 0x4028D81: strcat (mc_replace_strmem.c:176)
==2923==    by 0x8048523: concat (in /home/elias/Desktop/reSize2)
==2923==    by 0x8048624: main (in /home/elias/Desktop/reSize2)
==2923==  Address 0x41ca037 is 0 bytes after a block of size 15 free'd
==2923==    at 0x402896C: realloc (vg_replace_malloc.c:525)
==2923==    by 0x8048546: concat (in /home/elias/Desktop/reSize2)
==2923==    by 0x8048624: main (in /home/elias/Desktop/reSize2)
==2923== 
==2923== Invalid read of size 1
==2923==    at 0x804864A: main (in /home/elias/Desktop/reSize2)
==2923==  Address 0x41ca028 is 0 bytes inside a block of size 15 free'd
==2923==    at 0x402896C: realloc (vg_replace_malloc.c:525)
==2923==    by 0x8048546: concat (in /home/elias/Desktop/reSize2)
==2923==    by 0x8048624: main (in /home/elias/Desktop/reSize2)
==2923== 
==2923== Invalid read of size 1
==2923==    at 0x408A75C: vfprintf (vfprintf.c:1629)
==2923==    by 0x4092C9E: printf (printf.c:35)
==2923==    by 0x405F112: (below main) (libc-start.c:226)
==2923==  Address 0x41ca028 is 0 bytes inside a block of size 15 free'd
==2923==    at 0x402896C: realloc (vg_replace_malloc.c:525)
==2923==    by 0x8048546: concat (in /home/elias/Desktop/reSize2)
==2923==    by 0x8048624: main (in /home/elias/Desktop/reSize2)
==2923== 
==2923== Invalid read of size 1
==2923==    at 0x40B374B: _IO_file_xsputn@@GLIBC_2.1 (fileops.c:1317)
==2923==    by 0x4092C9E: printf (printf.c:35)
==2923==    by 0x405F112: (below main) (libc-start.c:226)
==2923==  Address 0x41ca036 is 14 bytes inside a block of size 15 free'd
==2923==    at 0x402896C: realloc (vg_replace_malloc.c:525)
==2923==    by 0x8048546: concat (in /home/elias/Desktop/reSize2)
==2923==    by 0x8048624: main (in /home/elias/Desktop/reSize2)
==2923== 
==2923== Invalid read of size 1
==2923==    at 0x40B375F: _IO_file_xsputn@@GLIBC_2.1 (fileops.c:1317)
==2923==    by 0x408A734: vfprintf (vfprintf.c:1629)
==2923==    by 0x4092C9E: printf (printf.c:35)
==2923==    by 0x405F112: (below main) (libc-start.c:226)
==2923==  Address 0x41ca035 is 13 bytes inside a block of size 15 free'd
==2923==    at 0x402896C: realloc (vg_replace_malloc.c:525)
==2923==    by 0x8048546: concat (in /home/elias/Desktop/reSize2)
==2923==    by 0x8048624: main (in /home/elias/Desktop/reSize2)
==2923== 
==2923== Invalid read of size 1
==2923==    at 0x40B36E8: _IO_file_xsputn@@GLIBC_2.1 (fileops.c:1349)
==2923==    by 0x408A734: vfprintf (vfprintf.c:1629)
==2923==    by 0x4092C9E: printf (printf.c:35)
==2923==    by 0x405F112: (below main) (libc-start.c:226)
==2923==  Address 0x41ca028 is 0 bytes inside a block of size 15 free'd
==2923==    at 0x402896C: realloc (vg_replace_malloc.c:525)
==2923==    by 0x8048546: concat (in /home/elias/Desktop/reSize2)
==2923==    by 0x8048624: main (in /home/elias/Desktop/reSize2)
==2923== 
==2923== Invalid read of size 1
==2923==    at 0x40B36F4: _IO_file_xsputn@@GLIBC_2.1 (fileops.c:1348)
==2923==    by 0x408A734: vfprintf (vfprintf.c:1629)
==2923==    by 0x4092C9E: printf (printf.c:35)
==2923==    by 0x405F112: (below main) (libc-start.c:226)
==2923==  Address 0x41ca02a is 2 bytes inside a block of size 15 free'd
==2923==    at 0x402896C: realloc (vg_replace_malloc.c:525)
==2923==    by 0x8048546: concat (in /home/elias/Desktop/reSize2)
==2923==    by 0x8048624: main (in /home/elias/Desktop/reSize2)
==2923== 
RES : ONETWOTHREEFIVE -- 15
==2923== Invalid free() / delete / delete[]
==2923==    at 0x4027C02: free (vg_replace_malloc.c:366)
==2923==    by 0x8048677: main (in /home/elias/Desktop/reSize2)
==2923==  Address 0x41ca028 is 0 bytes inside a block of size 15 free'd
==2923==    at 0x402896C: realloc (vg_replace_malloc.c:525)
==2923==    by 0x8048546: concat (in /home/elias/Desktop/reSize2)
==2923==    by 0x8048624: main (in /home/elias/Desktop/reSize2)
==2923== 
==2923== 
==2923== HEAP SUMMARY:
==2923==     in use at exit: 30 bytes in 1 blocks
==2923==   total heap usage: 2 allocs, 2 frees, 45 bytes allocated
==2923== 
==2923== LEAK SUMMARY:
==2923==    definitely lost: 30 bytes in 1 blocks
==2923==    indirectly lost: 0 bytes in 0 blocks
==2923==      possibly lost: 0 bytes in 0 blocks
==2923==    still reachable: 0 bytes in 0 blocks
==2923==         suppressed: 0 bytes in 0 blocks
==2923== Rerun with --leak-check=full to see details of leaked memory
==2923== 
==2923== For counts of detected and suppressed errors, rerun with: -v
==2923== ERROR SUMMARY: 80 errors from 12 contexts (suppressed: 11 from 6)

我对此有点困惑,因为我认为这不是必需的,因为该函数直接修改指针。

欢迎就如何改进此功能提出任何意见。

非常感谢,抱歉发了这么长的帖子。

最佳答案

当您在函数中修改 answer 时,您在函数范围内修改它,调用函数仍将看到旧值(自调用 realloc 以来该值无效)。

当您返回新指针并开始在调用函数中使用它时,一切正常。

解决此问题的最简单方法是使您的 concat 函数看起来像:

void concat(char** answer, char* src, unsigned int* limit, unsigned int* total) {
if((*limit - *total) > length)
  strcat(*answer, src); 
 else
 {
  *limit *= 2;
  *answer = realloc(*answer, sizeof(char)*(*limit));
  printf("RESIZING...\n");
  if(*answer == NULL)
  {  
   printf("RESIZING ERROR...\n"); 
   return NULL;
  }

  strcat(*answer, src); 
 }

 *total += length;
}

并这样调用它:

concat(&mem_block, strings[i], &LIMIT, &total);

但是,您应该将字符串抽象成它们自己的类型,而不是手动将它们的长度传递到一起。像这样的东西:

typedef struct _dynamic_string {
    char *s;
    unsigned int capacity;
    unsigned int length;
} dynamic_string;

应该是一个很好的起点,然后您就可以开始使用这个结构体来实现动态函数了。

关于c - C中的动态字符串连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12731389/

相关文章:

c - C 中查找数组中最小数字的算法

vector - 许多向量的垂直串联 Mata/Stata

go - 如何将 2 个文件合并或组合成单个文件

带有空字符串的 c 标记粘贴(连接)

MySQL 需要帮助将垂直数据格式化为水平数据

c++ - c++ 中的 +-ing 字符串和 <<-ing 字符串之间有什么区别吗?

条件编译策略——如何避免 C 语言中的 undefined symbol

c - 使用 ptrace 获取和设置多线程的 CPU 寄存器

c - 使用指针模拟简单函数的引用传递,但没有输出

c - 标准和禁食整数等价