我是否在此函数中造成了内存泄漏?
Have I created a memory leak in this function?
正在努力提高我的 C 技能。这个程序应该接受一个字符串并去掉它的空格。
我知道我已经两次调用 malloc
但只调用了一次 free
。我是否因此在某处获得了一些未释放的内存,或者因为我将原始指针分配给了新内存,它是否在我所做的一个 free
调用中全部消失了?
谢谢!
static void foo() {
char *string_to_change = malloc(sizeof(char) * 256);
strcpy(string_to_change, "my test");
printf("Before: %s\n", string_to_change); // "my test"
strip_whitespace(&string_to_change);
printf("After: %s\n", string_to_change); // "mytest"
free(string_to_change);
}
static void strip_whitespace(char **ptr) {
char *res = malloc(strlen(*ptr));
if (res == NULL)
exit_with_error(NULL_POINTER);
int current_pos = 0;
for (int i = 0; i < strlen(*ptr); i++) {
if (((*ptr)[i] == ' ') || ((*ptr)[i] == '\n' && ((*ptr)[i-1] == '\n' || (*ptr)[i+1] == '[=10=]'))) {
continue;
}
res[current_pos] = (*ptr)[i];
current_pos++;
}
res[current_pos] = '[=10=]';
*ptr = res;
}
你这里有漏洞:
*ptr = res;
在此行之前,*ptr
指向分配的内存块。然后将另一个分配块的起始地址分配给它,这意味着原始指针丢失了。你应该 free
就在这一行之前:
free(*ptr);
*ptr = res;
此外,此分配可能太少:
char *res = malloc(strlen(*ptr));
如果 *ptr
不包含要删除的空格,res
将没有足够的内存来保存终止空字节。您需要为此加 1。
char *res = malloc(strlen(*ptr) + 1);
确实,您的代码中存在内存泄漏。
假设您第一次调用 malloc
在地址 0x0010 分配内存,第二次调用在地址 0x0100 分配内存.您的 free 调用将有效地释放地址 string_to_change
处的内存,即 0x0100 但没有任何内容告诉编译器释放 [= 处的内存20=]0x0010.
通常,free
个调用确实与 malloc
个调用一样多。
KISS principle的意思是我们应该把代码写得越简单越好,而不是越复杂越好。即:
- 不要将分配和算法混为一谈。尽可能使用呼叫者分配。
- 除非有明显的需要,否则不要使用动态分配。
- 将字符串视为“不可变”通常是个好主意,除非有特定要求,否则不要对它们进行就地修改。
- 避免指针到指针和指针到指针的怪异算法。
- C 程序中
continue
的存在几乎可以肯定地表明存在不必要的复杂循环。
- 不要重新发明轮子。有
ctype.h
.
如果我们要通过调用者分配来实现它,代码可以归结为一些紧凑且易于阅读的代码,例如:
void strip_spaces (char* dst, const char* src)
{
while(*src != '[=10=]')
{
if(!isspace(*src))
{
*dst = *src;
dst++;
}
src++;
}
*dst = '[=10=]';
}
完整的程序:
#include <ctype.h>
#include <stdio.h>
void strip_spaces (char* dst, const char* src)
{
while(*src != '[=11=]')
{
if(!isspace(*src)) // if not string
{
*dst = *src; // then copy
dst++;
}
src++;
}
*dst = '[=11=]';
}
int main (void)
{
char str[] = " weird \n\r string contain ing spac\tes\n";
char stripped[128];
strip_spaces(stripped, str);
puts(stripped);
}
正在努力提高我的 C 技能。这个程序应该接受一个字符串并去掉它的空格。
我知道我已经两次调用 malloc
但只调用了一次 free
。我是否因此在某处获得了一些未释放的内存,或者因为我将原始指针分配给了新内存,它是否在我所做的一个 free
调用中全部消失了?
谢谢!
static void foo() {
char *string_to_change = malloc(sizeof(char) * 256);
strcpy(string_to_change, "my test");
printf("Before: %s\n", string_to_change); // "my test"
strip_whitespace(&string_to_change);
printf("After: %s\n", string_to_change); // "mytest"
free(string_to_change);
}
static void strip_whitespace(char **ptr) {
char *res = malloc(strlen(*ptr));
if (res == NULL)
exit_with_error(NULL_POINTER);
int current_pos = 0;
for (int i = 0; i < strlen(*ptr); i++) {
if (((*ptr)[i] == ' ') || ((*ptr)[i] == '\n' && ((*ptr)[i-1] == '\n' || (*ptr)[i+1] == '[=10=]'))) {
continue;
}
res[current_pos] = (*ptr)[i];
current_pos++;
}
res[current_pos] = '[=10=]';
*ptr = res;
}
你这里有漏洞:
*ptr = res;
在此行之前,*ptr
指向分配的内存块。然后将另一个分配块的起始地址分配给它,这意味着原始指针丢失了。你应该 free
就在这一行之前:
free(*ptr);
*ptr = res;
此外,此分配可能太少:
char *res = malloc(strlen(*ptr));
如果 *ptr
不包含要删除的空格,res
将没有足够的内存来保存终止空字节。您需要为此加 1。
char *res = malloc(strlen(*ptr) + 1);
确实,您的代码中存在内存泄漏。
假设您第一次调用 malloc
在地址 0x0010 分配内存,第二次调用在地址 0x0100 分配内存.您的 free 调用将有效地释放地址 string_to_change
处的内存,即 0x0100 但没有任何内容告诉编译器释放 [= 处的内存20=]0x0010.
通常,free
个调用确实与 malloc
个调用一样多。
KISS principle的意思是我们应该把代码写得越简单越好,而不是越复杂越好。即:
- 不要将分配和算法混为一谈。尽可能使用呼叫者分配。
- 除非有明显的需要,否则不要使用动态分配。
- 将字符串视为“不可变”通常是个好主意,除非有特定要求,否则不要对它们进行就地修改。
- 避免指针到指针和指针到指针的怪异算法。
- C 程序中
continue
的存在几乎可以肯定地表明存在不必要的复杂循环。 - 不要重新发明轮子。有
ctype.h
.
如果我们要通过调用者分配来实现它,代码可以归结为一些紧凑且易于阅读的代码,例如:
void strip_spaces (char* dst, const char* src)
{
while(*src != '[=10=]')
{
if(!isspace(*src))
{
*dst = *src;
dst++;
}
src++;
}
*dst = '[=10=]';
}
完整的程序:
#include <ctype.h>
#include <stdio.h>
void strip_spaces (char* dst, const char* src)
{
while(*src != '[=11=]')
{
if(!isspace(*src)) // if not string
{
*dst = *src; // then copy
dst++;
}
src++;
}
*dst = '[=11=]';
}
int main (void)
{
char str[] = " weird \n\r string contain ing spac\tes\n";
char stripped[128];
strip_spaces(stripped, str);
puts(stripped);
}