Форум — Ответы     (  К темам )
 ?  Valentin: Динамическая память (16-04-2003 17:32:47)
Возникла следующая проблема.
Моя программа должна считывать матрицу(вернее не совсем матрицу, а набор чисел)
и транспонировать ее(заменять строчки столбцами, а столбцы строчками), считывающуюся матрицу я загоняю в динамический массив и все бы хорошо, но возникает следующая проблема:
программа иногда работает а иногда и нет , пишет при этом что-то вроде "Null pointer assignment" .Подскажите где здесь ошибка:
#include <stdio.h>;
#include<conio.h>;
#include <alloc.h>
#include<string.h>;
void main(){
clrscr();
char l,l1[5],l2;
int k1,k2,k3,i,j,z,n,c,s,m,d,buf,max;
FILE *f,*f1;
int **a;
int *b;
s=0;
k2=0;
k3=0;
f=fopen("1.txt", "rt");
do
{
fscanf(f,"%c",&l);
if((l=='\n') && (!feof(f)))
k2=k2+1;
} while(!feof(f));
k2=k2+1;
b=(int *)calloc(k2+2,sizeof(int));
fclose(f);
f=fopen("1.txt", "rt");
printf("\n");
s=0;
k3=0;
i=0;
do
{
fscanf(f,"%s",&l1);
k3=k3+1;
fscanf(f,"%c",&l);

if ((l=='\n')&&(!feof(f)))
{
b[s]=k3;
s=s+1;
printf("\n");
k3=0;
}

}while(!feof(f));
b[s]=k3;
printf("\n max=%d s=%d \n",b[s],s);
for(i=0;i<=s;i++)
printf("\ b=%d\n",b[i]);

printf("\n\n");
max=b[0];
for(i=0;i<=s;i++)
if (b[i]>max) max=b[i];
if (s>max) max=s;
a=(int **)malloc(max*max);

fclose(f);
printf("\n");
f=fopen("1.txt","rt");

for(i=0;i<max;i++)
for(j=0;j<max;j++)
{
if(i<=s){
m=b[i];
if(j<m)
{
fscanf(f,"%d",&c);
fscanf(f,"%c",&l);

a[j][i]=c;
}
else
a[j][i]=0;
}
else
a[j][i]=0;
}

////////////////////////
fclose(f);
for(i=0;i<max;i++)
for(j=0;j<i;j++)
{
c=a[i][j];
a[i][j]=a[j][i];
a[j][i]=c;
}
//////////////////////


f=fopen("2.txt","wt");
c=0;
for(i=0;i<max;i++)
{

for(j=0;j<s;j++)
{
m=b[j];
if(i<m)
fprintf(f," %d",a[j][i]);
else
fprintf(f," ");
}
fprintf(f,"\n");
}
fclose(f);
free(a);
free(b);
}
 Георгий (16-04-2003 22:09:29)
Моё субьективное мнение:
для работы с памятью надо использовать одну пару функций (одну для удаления, другую для выделения), а у тебя то calloc, то malloc
если используешь C++ компилятор, то лучше использовать new и delete (как показывает практика — при создании древовидных структур с использованием malloc или calloc не совсем корректно освобождается память и, что самое интересное, глюк повторяется и у Borland C++ 3.1 и у Watcom C 11.0 — т.е. либо я неправильно работаю с malloc либо это общий глюк).

Практические советы:

1. используй new и delete:
b=(int *)calloc(k2+2,sizeof(int));
free b;
превращается в
b=(int *)new int[k2+2];
delete b; //тут вопрос ко всем — надо писать "delete b" или "delete[] b"?

2. программа судя по всему под DOS (хотя может быть и UNIX) а в досе память может кончиться — проверяй какой тебе указатель вернули — если нулевой, то памяти нет (в этом случае обычно exit(1))

3. я видел, что у тебя в цикле память выделяется, а освобождения в этом цикле не видел

4. когда закрываешь фигурную скобку пиши, к какому блоку она относится
например:
for (i=0;i<13;i++)
{
...
if (i>7)
{
...
}//if i>7
...
}//for...
так проше читать программу (спустя некоторое время)

5. нашёл ошибку:
int **a;
a=(int **)malloc(max*max);
a[j][i]=c;
эти 3 строчки бред:
int **a;
обьявляешь массив указателей на массив
a=(int **)malloc(max*max);
выделяешь место под массив указателей на массив
a[j][i]=c;
обрашаешся к j-му указателю на массив и в тот массив, адрес которого записан в j-м элементе массива a записываешь элемент.
НО кто будет выделять память под массив, на который указывает j-й элемент массива a??? — вот твоя программа и пошла гулять по памяти — жди разнообразных спец эффектов (начиная от нормальной работы и заканчивая проблемами и HDD — это я не пугаю — один раз был свидетелем того, как программа с таким глюком, кстати она тоже была учебной, вывела из строя HDD на 80MB, но это я видел только 1 раз)

лечится так:
int **a;
int i;
//выделение памяти
a=new int*[13];
for (i=0;i<13;i++) a[i]=new int[123];
//работа
...
обращения
a[i][j]=0;
i=a[i][j];
...
//освобождение памяти
for (i=0;i<13;i++) delete a[i];
delete a;

Также хочется отметить очень плохую структурированность кода...

ВЛАДИМИР:
когда же пробелы в начале строк будут писаться????
Код вообще читать нельзя!!!
Замучился...
 Alexander (17-04-2003 16:12:59)
1) Георгий, разумеется delete [] b . Подключи в C++Builder CodeGuard — он тебе тут же программу остановит и скажет 'resoure leak', если ты будешь удалять только delete b. Это все оттого, что в блоке выделяемой памяти нету информации о том, сколько там объектов живет. В java таких проблем нет.
2) Насчет программы — используй библиотеку stl и тип vector — это динамические массивы, самому ничего делать не надо. Они есть в Win32, Unix. Если ДОС — ну извините :)
3) Есть предложение в форуме, если уж HTML разрешить нельзя, хотя бы галочку сбоку 'форматированный текст' — чтобы автоматические вставлялся тег PRE и можно было бы код писать.
 Георгий (17-04-2003 21:28:18)
Alexander:
Не поверишь, но никакой разницы между delete[] b и delete b на уровне машинного кода нет
delete b — удаляет обьект b размером n*sizeof(int*)
а
delete[] b — удаляет массив элементов размером sizeof(int*) из n элементов
т.е. в результате осводождется один и тот же блок памяти (по длине)

а codeguard и так много глупостей пишет

если кто не согласен — пишите — будем обсуждать
 Георгий (18-04-2003 13:14:47)
всётаки я ошибся — код не совсем идентичный — стек вызовов:

delete[] a;
1. cc3250mt.@$bdla$qpv
2. cc3250mt.@$bdele$qpv
3. _free
4. [0x32585668]//судя по всему нечто системное

delete a;
1. cc3250mt.@$bdele$qpv
2. _free
3. [0x32585668]

как итог:
cc3250mt.@$bdla$qpv — вызывает cc3250mt.@$bdele$qpv и передаёт только адрес 'a' — т.е. это фактически заглушка, которая реально ничего не делает

вывод — в данной реализации компилятора C++ (BCB 5.0 Pro) нет никакой функциональной разницы между delete[] и delete

Хотелось бы услышать комментарии.
 Petro (18-04-2003 19:42:36)
2 Alexander:
>1) Георгий, разумеется delete [] b . Подключи в C++Builder CodeGuard — он тебе >тут же программу остановит и скажет 'resoure leak', если ты будешь удалять >только delete b.

И что, ему надо верить? :)))

>Это все оттого, что в блоке выделяемой памяти нету информации о том, сколько >там объектов живет.

b=(int *)new int[k2+2] — выделяет непрерывный блок памяти. delete b соответственно его освобождает.

>В java таких проблем нет.

Интересно, во сколько раз медленнее будет работать транспонирование, слепленное на жаве... :>

2 Георгий:
Если у тебя массив объектов — обязательно используй delete[]. В остальных случаях можно использовать просто delete.
 Георгий (19-04-2003 00:46:30)
Владимир — только что мой большой пост твой скрипт отверг со словами — error пусть он (скрипт) те слова, которые ему не нравятся заменяет на *** тогда хоть не придётся заново вдохновение искать, чтоб ответ написать
 Георгий (20-04-2003 13:16:12)
Petro:
delete[] — для массива обьектов вызывает деструктор для каждого элемента, а потом место, занимаемое массивом обьявляет свободным?
а
delete — просто место обьявляет свободным?
Petro я правильно тебя понял?
 Petro (21-04-2003 13:48:05)
yes