Сложность неправильной памяти? - PullRequest
2 голосов
/ 09 марта 2011

У меня есть этот «массив» указателей на структуры, изначально выделенные malloc, и мне нужно добавить дополнительную память с приращением, когда начальная емкость заполнится. Когда я пытаюсь выделить больше памяти, первый элемент исчезает и вызывает сбой моей программы. Кто-нибудь может помочь?

#include "a2.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int idCompare ( const void * a, const void * b ){
    message *m1 = *(message **)a;
    message *m2 = *(message **)b;
    return m1->messageId - m2->messageId;     
}

int textCompare( const void *a, const void *b ) {
    message *m1 = *(message **)a;
    message *m2 = *(message **)b;
    return strcmp(m1->messageText, m2->messageText);
}

int main(void)
{   
    int id, i;
    int count = 0;

    char cmd[MAX_CMD_LEN];
    char msg_text[MAX_TEXT_LEN];
    message **mList = malloc(INITIAL_CAPACITY * sizeof(message));
    int capacity = INITIAL_CAPACITY * sizeof(message);
    int size = 0;

    while (scanf("%s", cmd)){

        if (!strcmp(cmd, "add")){
            printf("(pre) Capacity =%d, Count =%d, Size =%d\n", capacity, count, size);
            int found = 0;
            scanf("%d\n", &id);
            fgets(msg_text, sizeof(msg_text), stdin);

            if(size >= capacity){
                capacity = size;
                *(mList + count) = malloc(CAPACITY_INCREMENT * sizeof(message));
                message *p = *(mList + count);                    
                if(p == NULL){                                          //If malloc fails, free mList and exit.
                    printf("out of memory\n");
                    free(*mList);
                    exit(1);
                }
            }   

            for(i = 0; i < count; i++){                                 //If existing id is found, send flag & do not add.
                message *p = *(mList + i);
                if(p->messageId == id){  found = 1;  }
            }

            if(!found){                                                
                message *p = *(mList + count);          
                p->messageId = id;
                p->messageText = malloc(strlen(msg_text)+1);    
                strcpy(p->messageText, msg_text);           
                count++;      
                size += 10 * sizeof(message);
                printf("(post) Capacity =%d, Count =%d, Size =%d\n", capacity, count, size);
            }
        }

        else if (!strcmp(cmd, "delete")){                       //Cycle through mList, if id is found, shift elements left.
        scanf("%d", &id);
        for(i = 0; i < count; i++){                
            message *p = *(mList + i);
                if(p->messageId == id){  
                    for(;i < count; i++){*(mList + i) = *(mList + i + 1);}
                    count--;
                    size -= 10 * sizeof(message); 
                }
            }  
        }

        else if (!strcmp(cmd, "find")){                                 //Cycle through mList, if id is matched, print to stdout.
        scanf("%d", &id);
        for(i = 0; i < count; i++){              
            message *p = *(mList + i);
                if(p->messageId == id){  printf("%s", p->messageText);  }
            } 
        }

        else if (!strcmp(cmd, "output")){                       //Cycle through mList, print all to stdout.
        for(i = 0; i < count; i++){
            message *p = *(mList + i);
                printf("%s", p->messageText);
            }
        }

        else if (!strcmp(cmd, "sortById")){  qsort (mList, count, sizeof(message*), idCompare);  }

        else if (!strcmp(cmd, "sortByText")){  qsort (mList, count, sizeof(message*), textCompare);  }

    }
    return 0;
}

Ответы [ 3 ]

4 голосов
/ 09 марта 2011

Во-первых, ваш список сообщений состоит из

message **mList

пока вы не используете его как указатель на список указателей. Вы никогда не размещаете указатели в списке!

Например, это будет «правильно» (хотя и неэффективно):

message **mList = malloc(INITIAL_CAPACITY * sizeof(message*));
for (i = 0; i < INITIAL; i++) {
   mList[i] = malloc(sizeof(message));
}

Теперь у вас есть структура данных, которую вы выразили.

Однако вы также можете выполнить:

message *mList = malloc(INITIAL_CAPACITY * sizeof(message));

Во всех случаях после устранения проблем с доступом к памяти вы можете использовать realloc() для изменения размера на месте.

0 голосов
/ 09 марта 2011

По крайней мере, судя по всему, вы неправильно определяете mlist:

message **mList = malloc(INITIAL_CAPACITY * sizeof(message));

Поскольку вы выделяете пространство для message структур, похоже, что mList должно быть просто message *:

message *mList = malloc(INITIAL_CAPACITY * sizeof(message));

или (что я обычно предпочитаю):

message *mList = malloc(INITIAL_CAPACITY * sizeof(*mList));

В целом, ваш код, похоже, сбивает с толку два довольно разных случая. Во-первых, вы динамически распределяете массив из message s, а во-вторых, вы выделяете массив указателей на сообщения. Хотя вопрос не является точным дубликатом, я ранее опубликовал ответ с диаграммами, чтобы графически показать разницу.

В то время как другие ответы верны, realloc, как правило, полезен для расширения выделения, я думаю, вам нужно немного больше подумать о том, что вы расширяете: массив message с или массив указатели, причем каждый фактический message выделяется индивидуально. Судя по всему, ваша структура message сама содержит указатель на такие вещи, как фактический текст сообщения, который выделяется отдельно от самой структуры message. В таком случае , вероятно, имеет больше смысла выделять массив объектов сообщений, а не массив указателей.

0 голосов
/ 09 марта 2011

Вам нужно использовать realloc(), чтобы увеличить выделенный блок памяти.

realloc() выделит новый блок (при необходимости), скопирует исходные данные в новый блок и освободит старый блок (при необходимости).

Если вы просто вызовете malloc() еще раз, вы выделите новый блок памяти с новыми значениями. Это также означает, что вы создали утечку памяти, потому что ваш оригинальный блок памяти не освобождается.

...