Модераторы: Daevaorn
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> free и двумерный динамический массив, экономим память 
:(
    Опции темы
EGD
Дата 25.10.2009, 23:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 25.10.2009

Репутация: нет
Всего: нет



начал делать задачку № 5.13 из незабвенной книги K&R и столкнулся с проблемой аварийного завершения программы при обращении к функции free()
собственно код программы:
Код
/*
* 5.13.c
*
*  Created on: 24.10.2009
*      Author: egd
*/
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
 
#define MAXLINE 100
#define FREE_MEM \
    {\
    for (i = n - j; i > 0; --i)\
    free(mass[i]);\
    free(mass);\
    exit(EXIT_FAILURE);\
    }
 
int main(int argc, char *argv[]) {
    int n, i, j = -1;
    char **mass, buff[MAXLINE + 1];
 
    if (argc != 2)
        n = 10;
    else if (argv[1][0] == '-' && isdigit(argv[1][1]))
        n = atoi(&argv[1][1]);
    if ((mass = malloc(n * sizeof(char *))) == NULL) {
        perror("malloc to mass");
        exit(EXIT_FAILURE);
    }
    memset(mass, 0, sizeof(mass));
    do {
        if ((buff = fgets(buff, MAXLINE, stdin)) == NULL && ferror(stdin)) {
            perror("fgets");
            FREE_MEM
        } else
            ++j;
        if (j == n) {
            free(mass[0]);
            for (i = 0; i < n - 1; ++i)
                mass[i] = mass[i + 1];
            j = n - 1;
        }
        if ((mass[j] = malloc(strlen(buff) * sizeof(char))) == NULL) {
            perror("calloc");
            FREE_MEM
        }
        if (buff)
            strcpy(mass[j], buff);
    } while (!feof(stdin));
 
    for (i = 0; i < n; ++i) {
        printf("%s", mass[i]);
        free(mass[i]);
    }
    free(mass);
    exit(EXIT_SUCCESS);
}

в кратце что она делает:
читает из stdin построчно и запносит в массив из argv[1] строк или 10 по умолчанию.
нужно вывести последние argv[1] строк (примерно тоже самое делает программа tail).
для экономии памяти, как и было написано в задании, я для каждой строки использовал минимум памяти.
если мы считали больше строк, чем может поместится в массиве - самую первую строку выталкиваем и сдвигаем все строки вверх, на освободившееся место помещаем новую.
и так далее пока не встретим EOF.
выводим что у нас получилось.

но при удалении первой строки получаем аварийное завершение с бектрейсом следующего содержания:
Цитата
> ./5.13 -3 < ../5.13.c                            
*** glibc detected *** ./5.13: free(): invalid pointer: 0x0804b020 ***                       
======= Backtrace: =========                                                                 
/lib/libc.so.6[0xb779e50b]                                                                   
/lib/libc.so.6(cfree+0xd9)[0xb77a3049]                                                       
./5.13[0x804892c]                                                                            
/lib/libc.so.6(__libc_start_main+0xfe)[0xb7747ace]                                           
./5.13[0x8048681]                                                                            
======= Memory map: ========                                                                 
...
ffffe000-fffff000 r-xp 00000000 00:00 0          [vdso]
Аварийный останов


а вот работающий код. отличие лишь в том, что для строк сразу задаем всю память, причем фиксированного размера MAXLINE. но это же очень расточительно! есть идея использовать связанный список, но задача поставлена на использовании массивов.
Код

/*
 * 5.13.c
 *
 *  Created on: 24.10.2009
 *      Author: egd
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define MAXLINE 100
#define FREE_MEM \
    {\
    for (; n > 0; --n)\
    free(mass[n]);\
    free(mass);\
    exit(EXIT_FAILURE);\
    }

int main(int argc, char *argv[]) {
    int n = 10, i, j;
    char **mass, *buff = malloc((MAXLINE + 1) * sizeof(char)); // 99 chars + '\0'

    if (argc == 2 && argv[1][0] == '-' && isdigit(argv[1][1]))
        if ((n = atoi(&argv[1][1])) == 0)
            exit(EXIT_SUCCESS);
    if ((mass = malloc(n * sizeof(char *))) == NULL) {
        perror("malloc to mass");
        exit(EXIT_FAILURE);
    }
    memset(mass, 0, sizeof(mass));
    for (j = 0; j < n; ++j)
        if ((mass[j] = malloc((MAXLINE + 1) * sizeof(char))) == NULL) {
            perror("calloc");
            FREE_MEM
        }
    j = 0;
    do {
        if ((buff = fgets(buff, MAXLINE - 1, stdin)) == NULL && ferror(stdin)) { // 99 chars + '\0'
            perror("fgets");
            FREE_MEM
        }
        if (++j == n) {
            if (buff) {
                for (i = 0; i != n - 1; ++i)
                    strcpy(mass[i], mass[i + 1]);
                strcpy(mass[i], buff);
                j = n - 1;
            } else
                break;
        } else {
            strcpy(mass[j - 1], buff);
        }
    } while (!feof(stdin));

    for (j = 0; j < n; ++j) {
        printf("%s", mass[j]);
        free(mass[j]);
    }
    free(mass);
    exit(EXIT_SUCCESS);
}


Это сообщение отредактировал(а) EGD - 26.10.2009, 12:20
PM   Вверх
niXman
Дата 26.10.2009, 00:55 (ссылка) |  (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 211
Регистрация: 4.7.2009

Репутация: 0
Всего: 0



Код

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
 
#define MAXLINE 100
#define FREE_MEM \
    {\
    for (i = n - j; i > 0; --i)\
    free(mass[i]);\
    free(mass);\
    exit(EXIT_FAILURE);\
    }
 
int main(int argc, char *argv[]) {
    int n, i, j = -1;
    char **mass, *del, buff[MAXLINE + 1];
 
    if (argc != 2)
        n = 10;
    else if (argv[1][0] == '-' && isdigit(argv[1][1]))
        n = atoi(&argv[1][1]);
    if ((mass = (char**)malloc(n * sizeof(char *))) == NULL) {
        perror("malloc to mass");
        exit(EXIT_FAILURE);
    }
    memset(mass, 0, sizeof(mass));
    do {
        if ((strcpy(buff, fgets(buff, MAXLINE, stdin))) == NULL && ferror(stdin)) {
            perror("fgets");
            FREE_MEM
        } else
            ++j;
        if (j == n) {
            free(mass[0]);
            for (i = 0; i < n - 1; ++i)
                mass[i] = mass[i + 1];
            j = n - 1;
        }
        if ((mass[j] = (char*)malloc(strlen(buff)+1 * sizeof(char))) == NULL) { /** +1 забыли */
            perror("calloc");
            FREE_MEM
        }
        if (buff)
            strcpy(mass[j], buff);
    } while (!feof(stdin));
 
    for (i = 0; i < n; ++i) {
        printf("%s", mass[i]);
        free(mass[i]);
    }
    free(mass);
    exit(EXIT_SUCCESS);
}


--------------------
if ( !c++ ) {   *power--;   this->wussiness += 10;}
PM MAIL   Вверх
EGD
Дата 26.10.2009, 12:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 25.10.2009

Репутация: нет
Всего: нет



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

после учета всех замечаний получилось следующее. с тем же результатом когда доходим до free()
Код

/*
 * 5.13.c
 *
 *  Created on: 26.10.2009
 *      Author: egd
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define MAXLINE 100
#define FREE_MEM \
    {\
    for (i = n - j; i > 0; --i)\
    free(mass[i]);\
    free(mass);\
    exit(EXIT_FAILURE);\
    }

int main(int argc, char *argv[]) {
    int n, i, j = -1;
    char **mass, buff[MAXLINE + 1];

    if (argc == 2 && argv[1][0] == '-' && isdigit(argv[1][1]))
        if ((n = atoi(&argv[1][1])) == 0)
            exit(EXIT_SUCCESS);
    if ((mass = malloc(n * sizeof(char *))) == NULL) {
        perror("malloc to mass");
        exit(EXIT_FAILURE);
    }
    memset(mass, 0, sizeof(mass));
    do {
        if (fgets(buff, MAXLINE - 1, stdin) == NULL && ferror(stdin)) {
            perror("fgets");
            FREE_MEM
            if (++j == n) {
                free(mass[0]);
                for (i = 0; i < n - 1; ++i)
                    mass[i] = mass[i + 1];
                j = n - 1;
            }
            if ((mass[j] = malloc(sizeof(buff) * sizeof(char))) == NULL) {
                perror("calloc");
                FREE_MEM
            }
            strcpy(mass[j], buff);
        }
    } while (!feof(stdin));

    for (i = 0; i < n; ++i) {
        printf("%s", mass[i]);
        free(mass[i]);
    }
    free(mass);
    exit(EXIT_SUCCESS);
}


Это сообщение отредактировал(а) EGD - 26.10.2009, 13:52
PM   Вверх
MAKCim
Дата 26.10.2009, 14:12 (ссылка) |    (голосов:2) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 52
Всего: 207



EGD, 
возьми valgrind


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
niXman
Дата 26.10.2009, 15:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 211
Регистрация: 4.7.2009

Репутация: 0
Всего: 0



Цитата(MAKCim @  26.10.2009,  12:12 Найти цитируемый пост)
возьми valgrind 

А в чем все же проблема? Просто нет сейчас возможности валгринд использовать.

Я исправил в своем коде, и все заработало. Только что попробовал запустить исходный код, та же ошибка. Вывод?...
--------------------
if ( !c++ ) {   *power--;   this->wussiness += 10;}
PM MAIL   Вверх
zim22
Дата 26.10.2009, 16:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


depict1
****


Профиль
Группа: Завсегдатай
Сообщений: 2682
Регистрация: 15.1.2009
Где: Украина

Репутация: 24
Всего: 69



Цитата(niXman @  26.10.2009,  14:44 Найти цитируемый пост)
. Вывод?...

вывод такой: или будем надеяться на Бога, чтобы программа не рухнула в самый неподходящий момент. или просмотрим исходник ещё раз. или глазами. или valgrind'oм.


--------------------
PM MAIL   Вверх
EGD
Дата 26.10.2009, 18:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 25.10.2009

Репутация: нет
Всего: нет



вот так работает и одновременно экономно. про sizeof я ступил. прошу прощения, больше не буду. правильно конечно же strlen + 1. изминений не много. я их выделил жирным. пытаюсь понять почему не работало до этого. спасибо за помощь.

еще посоветовали сделать вот что
Цитата
запусти эту прогу вот так:
MALLOC_CHECK_=0 ./a.out
у меня работает.
man free

Код

/*
 * 5.13.c
 *
 *  Created on: 26.10.2009
 *      Author: egd
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define MAXLINE 100
#define FREE_MEM \
    {\
    for (i = j; i > 0; --i)\
    free(mass[i]);\
    free(mass);\
    exit(EXIT_FAILURE);\
    }

int main(int argc, char *argv[]) {
    int n = 10, i, j = -1;
    char **mass, buff[MAXLINE + 1];

    if (argc == 2 && argv[1][0] == '-' && isdigit(argv[1][1]))
        if ((n = atoi(&argv[1][1])) == 0)
            exit(EXIT_SUCCESS);
    if ((mass = malloc(n * sizeof(char *))) == NULL) {
        perror("malloc to mass");
        exit(EXIT_FAILURE);
    }
    memset(mass, 0, sizeof(mass[0]) * n);
    do {
        *buff = 0;
        if (fgets(buff, MAXLINE - 1, stdin) == NULL && ferror(stdin)) {
            perror("fgets");
            FREE_MEM
        }
        if (++j == n) {
            free(mass[0]);
            for (i = 0; i < n - 1; ++i)
                mass[i] = mass[i + 1];
            j = n - 1;
        }
        if ((mass[j] = malloc((strlen(buff) + 1) * sizeof(char))) == NULL) {
            perror("calloc");
            FREE_MEM
        }
        strcpy(mass[j], buff);
    } while (!feof(stdin));
    n = j;
    for (i = 0; i < n; ++i) {
        printf("%s", mass[i]);
        free(mass[i]);
    }
    free(mass);
    puts("");
    exit(EXIT_SUCCESS);
}



Это сообщение отредактировал(а) EGD - 26.10.2009, 18:31
PM   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0500 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.