我知道这是一个非常常见的问题,但我想知道您对以下功能的看法。这个想法是这个函数可以连接字符串而不用担心结果大小:
#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)
但有一些我不喜欢的事情。我不想将这个变量//&lt; ----传递给函数。有没有更好的方法呢?而且如果我没有收到返回指针“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)
我对此有点困惑,因为我认为这不是必需的,因为函数会直接修改指针。
欢迎任何关于如何改进此功能的评论。
非常感谢,对于这篇长篇文章感到抱歉。
答案 0 :(得分:2)
当您修改函数中的答案时,仅在函数范围内修改它,调用函数仍然会看到旧值(因为您调用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;
应该是一个很好的起点,然后你可以使用这个结构来开始实现动态函数。
答案 1 :(得分:0)
您是否应该检查limit * 2
表达式是否低于当前限制+ length
?如果是这样,您需要增加限制。否则我认为你可以强制缓冲区溢出。
我认为你必须将你提到的变量作为指针传递,因为在某些情况下它们会被编辑。在语义上相同但在语法上“更容易”的可能替代方案可能是定义struct string
:
struct string {
char* buffer;
int limit;
int total;
};
这可以用来抽象出代表字符串的所有信息。
至于mem_block
问题,您必须收到它,因为按照realloc documentation:
The function may move the memory block to a new location, in which case the new location is returned.
因此,作为参数传递的字符串地址实际上可能与返回的字符串地址不同。您可以通过将指针作为参数传递给指针来修复它,所以当它更改时,您可以在适当的位置更新它:
void concat(char** answer, char* src, unsigned int* limit, unsigned int* total) {
/* When using strcat: */
strcat(*answer, src);
/* When reallocating */
*answer = realloc(*answer, *limit);
/* Also, sizeof(char) is always 1, by definition */
/* ... */
}
希望这有助于=)