Форум — Ответы ( К темам )
? | 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
|