【发布时间】:2021-12-15 14:20:01
【问题描述】:
每当我为我的编程运行测试代码时,它都会以以下消息终止:
free(): 在 tcache 2 中检测到双重空闲
进入 gdb 并使用“回溯”命令让我知道问题出在我的 String_Dispose 函数上。
(#5 0x000000000040131c in String_Dispose (ppStr=0x7fffffffdee0) at String.c:225)
这是我的 String_Dipose 函数代码:
/** Deallocates a String object and all its content.
*
* Pre:
* *ppStr is a pointer to a proper String object, so
* **ppStr is a proper String object
* **ppStr was allocated dynamically
* Post:
* (**ppStr).data has been deallocated
* **ppStr has been deallocated
* *ppStr == NULL
*/
void String_Dispose(String** ppStr) {
/// Implement this function!! ///
free((**ppStr).pData);
free(*ppStr);
*ppStr = NULL;
}
这是函数调用在实践中的样子:
String *pStr = String_Create("And as we wind on down the road...", 34);
. . .
// Initialize the String and use it until we're done with it.
. . .
String_Dispose(&pStr);
// At this point, every trace of the String object is gone and pStr == NULL
这是上下文的其余代码,我不确定它是否正确(它也未完成)但这里的主要问题是 String_Dipose。
#include "String.h"
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
/** The String is initialized to hold the values in *src.
*
* Pre:
* *pSrc is C string with length up to slength (excludes null char)
* Post on success:
* A new, proper String object S is created such that:
* S.pData != pSrc->pData
* Up to slength characters in *pSrc are copied into dest->data
* (after dynamic allocation) and the new string is terminated
* with a '\0'
* S.length is set to the number of characters copied from *pSrc;
* this is no more than slength, but will be less if a '\0' is
* encountered in *pSrc before slength chars have occurred
* Post on failure:
* NULL is returned
*
* Returns:
* pointer to the new String object;
* NULL value if some error occurs
*/
String* String_Create(const char* const pSrc, uint32_t slength) {
/// Implement this function!! ///
String* str = (String*) malloc(sizeof(String));
if (str == NULL) {
printf("Failed to allocate memory.");
return -1;
}
str->pData = pSrc;
str->length = slength;
return str;
}
/** Compares two Strings.
*
* Pre:
* *pLeft is a proper String object
* *pRight is is a proper String object
*
* Returns:
* < 0 if *pLeft precedes *pRight, lexically
* 0 if *pLeft equals *pRight
* > 0 if *pLeft follows *pRight, lexically
*/
int32_t String_Compare(const String* const pLeft, const String* const pRight) {
/// Implement this function!! ///
uint32_t left = 0, right = 0;
uint32_t leftLength = pLeft->length, rightLength = pRight->length;
while (left < leftLength && right < rightLength) {
int compare = pLeft->pData[left++] - pRight->pData[right++];
if (compare != 0) {
return compare;
}
}
return (pLeft->pData[left] - pRight->pData[right]);
}
/** Appends the String *pSrc to the String *pDest.
*
* Pre:
* *pDest is a proper String object
* *pSrc is is a proper String object
* pSrc != pDest (i.e., the source and destination are different String objects)
* Post on success:
* pSrc->pData is appended to the String pDest->pData
* *pDest is a proper String object
* Post on failure:
* *pDest is unchanged
*
* Returns:
* the length of pDest->pData, if nothing goes wrong;
* a negative value, if some error occurs
*/
int32_t String_Cat(String* const pDest, const String* const pSrc) {
/// Implement this function!! ///
uint32_t srcLength = pSrc->length, destLength = pDest->length;
char* strCmb = (char*) malloc(sizeof(char) * (srcLength + destLength + 1));
if (strCmb == NULL) {
printf("Failed to allocate memory.");
return -1;
}
uint32_t i = 0, j = 0;
while (j < destLength) {
strCmb[i++] = pDest->pData[j++];
}
j = 0;
while (j < srcLength) {
strCmb[i++] = pDest->pData[j++];
}
strCmb[i] = '\0';
pDest->pData = strCmb;
pDest->length = i;
return pDest->length;
}
/** Makes an exact, full copy of a substring.
*
* Pre:
* *pSrc is a proper String object
* startIdx + length <= pSrc->length
* Post:
* no memory leaks have occurred
* A new, proper string object S has been created such that S holds
* the specified substring of *pSrc
*
* Returns:
* pointer to a String object which holds a copy of specified substring;
* NULL if failure occurs
*/
String* String_subString(const String* const pSrc, uint32_t start, uint32_t length) {
/// Implement this function!! ///
String* subStr = (String*) malloc(sizeof(String));
if (subStr == NULL) {
printf("Failed to allocate memory.");
return -1;
}
subStr->pData = NULL;
subStr->length = length + 1;
char* strData = (char*) malloc(sizeof(char) * (length + 1));
int i = start, j = 0;
while (i < length) {
strData[j] = pSrc->pData[i];
j++;
}
strData[j+1] = "\0";
subStr->pData = strData;
return subStr;
}
/** Erases a specified sequence of characters from a String.
*
* Pre:
* *pSrc is a proper String object
* startIdx + length <= src->length
* Post:
* no memory leaks have occurred
* the specified range of characters have been removed
* *pSrc is proper
*
* Returns:
* if successful, pSrc
* NULL if failure occurs
*/
String* String_Erase(String* const pSrc, uint32_t start, uint32_t length) {
/// Implement this function!! ///
return pSrc;
}
/** Deallocates a String object and all its content.
*
* Pre:
* *ppStr is a pointer to a proper String object, so
* **ppStr is a proper String object
* **ppStr was allocated dynamically
* Post:
* (**ppStr).data has been deallocated
* **ppStr has been deallocated
* *ppStr == NULL
*/
void String_Dispose(String** ppStr) {
/// Implement this function!! ///
free((**ppStr).pData);
free(*ppStr);
*ppStr = NULL;
}
不知道是什么问题,我也试过了:
String* ptr = *ppStr;
free (ptr->data);
free (ptr);
*ppStr= NULL;
这最终会得到相同的结果,我有点迷茫,希望朝着正确的方向前进。
String.h 中的结构声明:
struct _String {
char *pData; // dynamically-allocated array to hold the characters
uint32_t length; // number of characters in the string
};
typedef struct _String String;
【问题讨论】:
-
我忘了显示 String.h,但结构的声明非常简单,有两个字段:char *pData 和 uint32_t 长度。
-
将声明添加到问题中。不要发表评论。
-
为什么你的'String_Create()`函数没有复制字符串数据?你的类型没有管理它的所有资源;它无法控制其他代码的滥用。很难阅读所有 cmets 以了解您的代码在做什么。但是,您将一行显示为
String *pStr = String_Create("And as we wind on down the road...", 34);— 该字符串不是由malloc()分配的,因此无法安全地释放它。如果该类型复制了它传递的数据,那么正是可以避免的问题。 -
不是malloc分配的吗?在 String_Create() 函数中,我调用 malloc 然后返回该字符串。我也不确定你在通过函数本身传递字符串数据时复制它是什么意思。
-
@Azure21 我相信 JonathanLeffler 是正确的。我自己的测试代码使用了您的 String_Create 并且没有错误地运行,但是如果我尝试使用 您的示例代码,那么我会得到您发布的错误。
标签: c pointers memory-management free