我正在嘗試制作一個小型庫來處理字串,因為在 C 中處理它們例外復雜。
我有一個這樣定義的結構:
typedef struct _String
{
unsigned int size;
char *string;
} String;
它非常簡單,并允許我動態更改陣列大小(前提是我正確使用它)。
我有一個專門用于創建此結構的函式,以及一個使用指向String.
String *create_string(char *chr)
{
String *str = calloc(1, sizeof(unsigned int) sizeof(chr));
str->string = chr;
str->size = strlen(chr);
return str;
}
void destroy_string(String *str)
{
free(str);
}
但無論如何,我在制作一個定義如下的連接函式時遇到了問題:
bool concat_string_char(String *str, char *chr)
{
// No use to continue since the passed String isn't initialized
if (str->string == NULL) return false;
// Storing the previous string pointer
char *ptr = str->string;
// Final size after concat
int final_size = str->size strlen(chr);
// Allocating a new block of memory of size final_size * sizeof(char)
str->string = calloc(1, final_size * sizeof(char));
// Append each characters of orignal string
for (int i = 0; i != str->size; i )
{
str->string[i] = ptr[i];
}
// append each character of chr
for (int i = 0; i != strlen(chr); i )
{
str->string[str->size ] = chr[i];
}
// Free the memory allocated by the previous string -> Crash
free(ptr);
return true;
}
正如我所評論的,當我在原始字串使用的指標處釋放記憶體時會發生崩潰。
包括:
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
您可以嘗試使用上面的 3 個函式,如下所示(前提是您發表評論free():
int main(void)
{
String *str = create_string("Original");
concat_string_char(str, " Concatenated");
printf("%s\n", str->string);
destroy_string(str);
return 0;
}
轉載:https ://replit.com/@Mrcubix-Mrcubix/String-test#main.c
/EDIT: The Output string is indeed the one expected, the only issue here is to free this old pointer to not leak memory. END/
I tried using gdb to see if i could debug anything but as always, debugger have only ever been useful in cases where i couldn't find the location of crashes, never to figure out issues.
But anyway, it anyone would like to point out my mistake and explain in further details why it's wrong, i think it would improve my understanding of pointer in these kind of situations.
uj5u.com熱心網友回復:
這就是你的錯誤:
String *create_string(char *chr)
{
String *str = calloc(1, sizeof(unsigned int) sizeof(chr));
str->string = chr;
str->size = strlen(chr);
return str;
}
第一個問題在這里:
String *str = calloc(1, sizeof(unsigned int) sizeof(chr));
您正在為整個結構分配記憶體,包括str->string. 我明白了,這可以防止堆碎片,但也會使操作復雜化。
Calingfree上str->string會導致段錯誤,因為該地址是無效的。你只能叫free上str。
第二:
str->string = chr;
這不是復制字串,這只是分配指標。那是完全錯誤的。您必須使用 memcpy 或類似工具進行復制:
memcpy(res->string, value, res->size);
第三:這可能有效:
String *create_string(char *chr)
{
String *str = malloc(sizeof(String));
str->size = strlen(chr);
str->string = malloc(str->size);
memcpy(res->string, value, res->size);
return str;
}
而且,如果要添加終止 NULL 字符,請嘗試以下操作:
void destroy_string(String *str)
{
free(str->string);
free(str);
}
最后:您沒有設定終止NULL字符,列印時請記住這一點(例如:使用標準列印功能)。
如果要添加終止NULL字符,請將建構式更改為此。
String *create_string(char *chr)
{
String *str = malloc(sizeof(String));
str->size = strlen(chr);
str->string = malloc(str->size 1);
memcpy(res->string, value, res->size);
str->string[str->size] = '\0';
return str;
}
當然,您需要在 concat 函式中考慮到這一點。
注意:您可以通過從源字串中復制空字符來避免第二次賦值,因為 C 中的所有字串都以 NULL 結尾(感謝@0___________):
memcpy(res->string, value, res->size 1);
更新:您使用calloc不正確:
str->string = calloc(1, final_size * sizeof(char));
正確的用法是:
str->string = calloc(final_size, sizeof(char));
uj5u.com熱心網友回復:
您的代碼在很多地方都無效:
- 使用
size_t的大小
String *str = calloc(1, sizeof(unsigned int) sizeof(chr));
它可能不會為結構分配足夠的空間,因為它對填充一無所知
str->string = chr;
你需要復制它。但是您沒有為字串分配任何記憶體。賦值不會為其分配記憶體或復制字串內容。
在concat_string_char您嘗試釋放未動態分配的指標時 - 因此崩潰。
我會以其他方式實作它:
typedef struct String
{
size_t size;
char string[];
} String;
String *create_string(const char * restrict chr)
{
size_t len = strlen(chr);
String *str = malloc(sizeof(*str) len 1);
if(str)
{
str->size = len;
memcpy(str -> string, chr, len 1);
}
return str;
}
void destroy_string(String *str)
{
free(str);
}
String *concat_string_char(String *str, char *chr)
{
size_t len;
if(str)
{
str = realloc(sizeof(*str) str > size (len = strlen(chr)) 1);
if(str)
{
strcpy(str -> data str -> size, chr);
str -> size = len;
}
}
return str;
}
uj5u.com熱心網友回復:
我認為 ptr 變數根本沒有泄漏記憶體。因為它只是一個指向實際字串開頭的指標,它被放置在堆疊上而不是堆上,因為單個指標只是一個整數,如果您在函式中宣告它們,它們也會釋放自己。如果存在記憶體泄漏,它可能來自這里:
str->string = calloc(1, final_size * sizeof(char));
因為您在堆上為 str 結構分配新記憶體而不釋放之前存盤在那里的內容。所以你可以free(str);在為連接的字串分配記憶體之前嘗試。您正在分配記憶體并從 calloc() 獲取指向它的指標,但未連接的字串的記憶體仍在堆中,您只是不再擁有指向它的指標。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/368913.html
標籤:c string pointers memory free
