在尝试释放内存部分时,我似乎崩溃了我的程序。以下是我的链接列表的整体结构:
typedef struct {
char *dataitem;
struct listelement *link;
int16_t wordSize;
int16_t (*libWord)[Q];
char gpioValue;
struct listelement *syllables;
}listelement;
调用此函数时程序崩溃:
recordedWordsPointer = RemoveItem(recordedWordsPointer); // get rid of any junk stored in the recorded buffer
其中:
volatile listelement *recordedWordsPointer;
在libWord中存储了值,如果有另一个则指向下一个链接,否则为NULL。以下显示输入功能时会发生什么:
listelement * RemoveItem (listelement * listpointer) {
cpu_irq_disable();
listelement * tempp = listpointer;
while( listpointer->syllables != NULL ){
RemoveSyllable(listpointer->syllables);
}
if( listpointer != NULL ){
tempp = listpointer -> link;
free (listpointer->dataitem);
free (listpointer->libWord);
free (listpointer);
}
cpu_irq_enable();
return tempp;
}
void RemoveSyllable (listelement * listpointer) {
while( listpointer->syllables != NULL ){
RemoveSyllable(listpointer->syllables);
}
free (listpointer->dataitem);
free (listpointer->libWord);
free (listpointer);
listpointer = NULL;
return;
}
我想知道我是否做错了导致内存崩溃?
谢谢!
编辑:
我被要求展示如何构建内存位置以提供帮助。我使用以下两个函数:
listelement * AddItem (listelement * listpointer, char* name, int16_t size, int16_t wordLength, int16_t (*words)[Q]) {
// returns listPointer at the beginning of list
listelement * lp = listpointer;
listelement * listPointerTemp;
char ErrorHandler = NULL;
// are we at the end of the list?
if (listpointer != NULL) {
// move down to the end of the list
while (listpointer -> link != NULL)
listpointer = listpointer -> link;
listPointerTemp = listpointer;
listpointer -> link = (struct listelement *) malloc (sizeof (listelement));
// on fail end links becomes NULL already above
if(listpointer -> link != NULL){
listpointer = listpointer -> link;
listpointer -> link = NULL;
listpointer -> wordSize = wordLength;
listpointer -> syllables = NULL;
listpointer -> dataitem = (char*) malloc ((size + 1)*sizeof(char));
if(listpointer -> dataitem != NULL){
for(int i=0; i<size ; i++){
listpointer -> dataitem[i] = name[i];
}
listpointer -> dataitem[size] = NULL;
listpointer -> libWord = (int16_t(*)[Q])malloc(wordLength*Q*sizeof(int16_t));
if(listpointer -> libWord != NULL){
for (int16_t row=0 ; row < wordLength ; row++){
for (int col=0 ; col < Q ; col++){
listpointer -> libWord[row][col] = words[row][col];
}
}
ErrorHandler = 1;
}else{
free(listpointer->dataitem);
free(listpointer);
listPointerTemp -> link = NULL;
}
}else{
free(listpointer);
listPointerTemp -> link = NULL;
}
}
if(ErrorHandler == NULL){
//failure
usart_write_line(&AVR32_USART0,"\r\n--------------------------------------------\r\n");
usart_write_line(&AVR32_USART0,"Ran out of Memory! Word not created.\r\n");
usart_write_line(&AVR32_USART0,"\r\n--------------------------------------------\r\n");
}
return lp;
} else {
listpointer = (struct listelement *) malloc (sizeof (listelement));
if(listpointer != NULL){
listpointer -> link = NULL;
listpointer -> wordSize = wordLength;
listpointer -> syllables = NULL;
listpointer -> dataitem = (char*) malloc ((size + 1)*sizeof(char));
if(listpointer -> dataitem != NULL){
for(int16_t i=0; i<size ; i++){
listpointer -> dataitem[i] = name[i];
}
listpointer -> dataitem[size] = NULL;
listpointer -> libWord = (int16_t(*)[Q])malloc(wordLength*Q*sizeof(int16_t));
if(listpointer -> libWord != NULL){
for (int16_t row=0 ; row < wordLength ; row++){
for (int col=0 ; col < Q ; col++){
listpointer -> libWord[row][col] = words[row][col];
}
}
ErrorHandler = 1;
}else{
free(listpointer->dataitem);
free(listpointer);
listPointerTemp -> link = NULL;
}
}else{
free(listpointer);
listPointerTemp -> link = NULL;
}
}
if(ErrorHandler == NULL){
//failure
usart_write_line(&AVR32_USART0,"\r\n--------------------------------------------\r\n");
usart_write_line(&AVR32_USART0,"Ran out of Memory! Word not created.\r\n");
usart_write_line(&AVR32_USART0,"\r\n--------------------------------------------\r\n");
}
return listpointer;
}
}
listelement* AddSyllable (listelement * listpointer, char* name, int16_t size, int16_t wordLength, int16_t (*words)[Q]) {
// returns listPointer at the beginning of list
listelement * lp = listpointer;
listelement * listPointerTemp;
char ErrorHandler = NULL;
// are we at the end of the list?
if (listpointer != NULL) {
// move down to the end of the list
while (listpointer -> syllables != NULL)
listpointer = listpointer -> syllables;
listPointerTemp = listpointer;
listpointer -> syllables = (struct listelement *) malloc (sizeof (listelement));
// on fail end links becomes NULL already above
if(listpointer -> syllables != NULL){
listpointer = listpointer -> syllables;
listpointer -> link = NULL;
listpointer -> wordSize = wordLength;
listpointer -> dataitem = (char*) malloc ((size + 1)*sizeof(char));
if(listpointer -> dataitem != NULL){
for(int i=0; i<size ; i++){
listpointer -> dataitem[i] = name[i];
}
listpointer -> dataitem[size] = NULL;
listpointer -> libWord = (int16_t(*)[Q])malloc(wordLength*Q*sizeof(int16_t));
if(listpointer -> libWord != NULL){
for (int16_t row=0 ; row < wordLength ; row++){
for (int col=0 ; col < Q ; col++){
listpointer -> libWord[row][col] = words[row][col];
}
}
ErrorHandler = 1;
}else{
free(listpointer->dataitem);
free(listpointer);
listPointerTemp -> syllables = NULL;
}
}else{
free(listpointer);
listPointerTemp -> syllables = NULL;
}
}
if(ErrorHandler == NULL){
//failure
usart_write_line(&AVR32_USART0,"\r\n--------------------------------------------\r\n");
usart_write_line(&AVR32_USART0,"Ran out of Memory! Word not created.\r\n");
usart_write_line(&AVR32_USART0,"\r\n--------------------------------------------\r\n");
}
return lp;
} else {
listpointer = (struct listelement *) malloc (sizeof (listelement));
if(listpointer != NULL){
listpointer -> link = NULL;
listpointer -> wordSize = wordLength;
listpointer -> dataitem = (char*) malloc ((size + 1)*sizeof(char));
if(listpointer -> dataitem != NULL){
for(int16_t i=0; i<size ; i++){
listpointer -> dataitem[i] = name[i];
}
listpointer -> dataitem[size] = NULL;
listpointer -> libWord = (int16_t(*)[Q])malloc(wordLength*Q*sizeof(int16_t));
if(listpointer -> libWord != NULL){
for (int16_t row=0 ; row < wordLength ; row++){
for (int col=0 ; col < Q ; col++){
listpointer -> libWord[row][col] = words[row][col];
}
}
ErrorHandler = 1;
}else{
free(listpointer->dataitem);
free(listpointer);
listPointerTemp -> syllables = NULL;
}
}else{
free(listpointer);
listPointerTemp -> syllables = NULL;
}
}
if(ErrorHandler == NULL){
//failure
usart_write_line(&AVR32_USART0,"\r\n--------------------------------------------\r\n");
usart_write_line(&AVR32_USART0,"Ran out of Memory! Word not created.\r\n");
usart_write_line(&AVR32_USART0,"\r\n--------------------------------------------\r\n");
}
return listpointer;
}
}
答案 0 :(得分:2)
您的RemoveSyllable函数实际上并未将syllables
成员设置为NULL。你认为它在例程中,但实际上你只是在局部变量中改变它的值。
答案 1 :(得分:1)
这是对代码的部分解构,而不是完整的答案。
您是否打开了编译器警告?如果没有,为什么不呢?
typedef struct {
char *dataitem;
struct listelement *link;
int16_t wordSize;
int16_t (*libWord)[Q];
char gpioValue;
struct listelement *syllables;
} listelement
请注意,link
和syllables
成员并未将您struct
的匿名typedef
指向listelement
。他们指出了一些其他完全不相关的结构。编译器对此抱怨不已 - 有充分的理由。修复很简单:将typedef struct {
更改为typedef struct listelement {
。但是我们不应该在你的代码中处理这么多混乱。
您有时也会误用NULL
。例如,char ErrorHandler = NULL;
生成警告,指针正在转换为不同大小的整数。 NULL
不一定是0;它至少有时是((void *)0)
或类似的东西。您还使用NULL代替'\0'
将字符串的结束字节设置为空字节 - 这也会引发编译器警告。这些都是嘈杂而不是非常严重,但你应该瞄准那些用最少的转换来静默编译的代码(也就是说,不要简单地在所有地方强制转换来关闭编译器警告)。
你写道:
if(listpointer -> link != NULL){
忽略大括号的位置(受到合法辩论),你应该在if
后面留一个空格,->
周围不能有任何空格。关于空格的类似评论适用于while
;在调用和定义中,在函数名和左括号之间不使用空格也是常规的。
这个警告很严重:
usart.c:297:5: warning: passing argument 1 of ‘RemoveItem’ discards ‘volatile’ qualifier from pointer target type [enabled by default]
usart.c:253:14: note: expected ‘struct listelement *’ but argument is of type ‘volatile struct listelement *’
基本上,当您拨打recordedWordsPointer
时,会移除RemoveItem
的易变性,这会使volatile
的存在变得多余。如果是volatile
,则必须确保使用它的所有地方都知道这一点。或者,更简单地说,删除volatile
限定符。
每个AddItem()
和AddSyllable()
似乎都存在大量代码重复。你的目标应该是消除每个功能的一半左右。
现在我必须使用我们如何真正使用这些功能,这样才能看出出了什么问题。这很难,尤其是因为AddItem()
和AddSyllable()
函数的参数包括一个神秘的int16_t (*words)[Q]
。如果你能展示一个简单的main()
程序,它可以用适当的参数调用这些函数(它应该是初始化的数据结构,而不是从文件读取的值),这将有所帮助。
减少代码量的一个关键重构是创建一个函数,使listelement
给出名称,大小,单词数和单词。以下dupstr()
功能与strdup()
不同;它需要一个长度并复制一个可能更长的字符串的许多字符。
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
enum { Q = 16 };
typedef struct listelement
{
char *dataitem;
struct listelement *link;
int16_t wordSize;
int16_t (*libWord)[Q];
struct listelement *syllables;
} listelement;
static int AVR32_USART0 = 0;
static void cpu_irq_disable(void);
static void cpu_irq_enable(void);
static void usart_write_line(int *ptr, char *msg);
extern void RemoveSyllable(listelement *listpointer);
extern listelement *RemoveItem(listelement *listpointer);
extern listelement *AddSyllable(listelement *listpointer, char *name, int16_t size, int16_t wordLength, int16_t (*words)[Q]);
extern listelement *AddItem(listelement *listpointer, char *name, int16_t size, int16_t wordLength, int16_t (*words)[Q]);
/* Duplicate string - or use POSIX strdup() */
static char *dupstr(const char *name, int16_t size)
{
char *str = malloc(size+1);
if (str != NULL)
{
memmove(str, name, size);
str[size] = '\0';
}
return str;
}
static listelement *makeElement(const char *name, int16_t size, int16_t wordLength, int16_t (*words)[Q])
{
listelement *listpointer = (listelement *)malloc(sizeof(listelement));
// on fail end links becomes NULL already above
if (listpointer != NULL)
{
listpointer->dataitem = dupstr(name, size);
listpointer->libWord = (int16_t(*)[Q])malloc(wordLength*Q*sizeof(int16_t));
if (listpointer->dataitem == NULL || listpointer->libWord == 0)
{
free(listpointer->dataitem);
free(listpointer->libWord);
free(listpointer);
listpointer = NULL;
}
else
{
listpointer->link = NULL;
listpointer->wordSize = wordLength;
listpointer->syllables = NULL;
for (int16_t row=0; row < wordLength; row++)
{
for (int col=0; col < Q; col++)
{
listpointer->libWord[row][col] = words[row][col];
}
}
}
}
return listpointer;
}
static void reportError(void)
{
usart_write_line(&AVR32_USART0,"\r\n--------------------------------------------\r\n");
usart_write_line(&AVR32_USART0,"Ran out of Memory! Word not created.\r\n");
usart_write_line(&AVR32_USART0,"\r\n--------------------------------------------\r\n");
}
listelement *AddItem(listelement *listpointer, char *name, int16_t size, int16_t wordLength, int16_t (*words)[Q])
{
listelement *lp = listpointer;
char ErrorHandler = 0;
if (listpointer != NULL)
{
while (listpointer->link != NULL)
listpointer = listpointer->link;
listpointer->link = makeElement(name, size, wordLength, words);
if (listpointer->link != NULL)
{
listpointer = listpointer->link;
ErrorHandler = 1;
}
}
else
{
listpointer = makeElement(name, size, wordLength, words);
if (listpointer != NULL)
ErrorHandler = 1;
lp = listpointer;
}
if (ErrorHandler == 0)
reportError();
return lp;
}
listelement *AddSyllable(listelement *listpointer, char *name, int16_t size, int16_t wordLength, int16_t (*words)[Q])
{
listelement *lp = listpointer;
char ErrorHandler = 0;
if (listpointer != NULL)
{
while (listpointer->syllables != NULL)
listpointer = listpointer->syllables;
listpointer->syllables = makeElement(name, size, wordLength, words);
if (listpointer->syllables != NULL)
ErrorHandler = 1;
}
else
{
listpointer = makeElement(name, size, wordLength, words);
if (listpointer != NULL)
ErrorHandler = 1;
lp = listpointer;
}
if (ErrorHandler == 0)
reportError();
return lp;
}
listelement *RemoveItem(listelement *listpointer)
{
cpu_irq_disable();
listelement * tempp = listpointer;
while (listpointer->syllables != NULL)
{
RemoveSyllable(listpointer->syllables);
}
if (listpointer != NULL)
{
tempp = listpointer->link;
free (listpointer->dataitem);
free (listpointer->libWord);
free (listpointer);
}
cpu_irq_enable();
return tempp;
}
void RemoveSyllable(listelement *listpointer)
{
while (listpointer->syllables != NULL)
{
RemoveSyllable(listpointer->syllables);
}
free(listpointer->dataitem);
free(listpointer->libWord);
free(listpointer);
listpointer = NULL;
return;
}
static void cpu_irq_disable(void) { AVR32_USART0 = 0; }
static void cpu_irq_enable(void) { AVR32_USART0 = 1; }
static void usart_write_line(int *ptr, char *msg)
{
*ptr = !*ptr;
fprintf(stderr, "%s", msg);
}
int main(void)
{
listelement *recordedWordsPointer = 0;
recordedWordsPointer = RemoveItem(recordedWordsPointer);
}
我没有证明那里的每一个变化都有声音,但我确信addSyllable()
和addItem()
函数使用makeElement()
函数更容易阅读整个堆做了大部分的重复工作。毫无疑问,还有改进的余地。代码需要一个真正运行函数的工作main()
(并且上面的代码不符合条件)。
我对如何处理指向数组的指针有所保留,但是我没有把代码带到我可以有用地运行valgrind
的机器上(遗憾的是Mac OS X 10.8.x不受{ {1}},但)。我没有证明这是错的;我怀疑它是错的。它将帮助我无法看到调用代码,并将变量的定义作为指向数组的指针传递。