|
Programiranje Programski jezici, tehnike, alatke... |
|
Alatke vezane za temu | Vrste prikaza |
7.8.2017, 18:31 | #1 |
Član
Član od: 13.3.2017.
Poruke: 55
Zahvalnice: 30
Zahvaljeno 3 puta na 3 poruka
|
C program i curenje memorije
Pokušao sam da napravim program koji čita sa standardnog ulaza jedan red (tj. do znaka '\n'), i svaku rec ubacuje u ulančanu listu. Problem je što mi valgrind prijavljuje da imam više alokacija nego dealokacija memorije. Da li neko vidi gde je problem?
Kod:
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> #define ALLOCCHECK(x) if ((x) == NULL) exit(-2) typedef struct node { char* word; struct node* next; } Node; void delete_list(Node* list) { Node* old; while(list) { old = list; list = list->next; free(old->word); free(old); } } Node* add_to_list(Node* line, char* word) { Node* current; Node* new_node =(Node*) malloc(sizeof(Node)); new_node->next = NULL; new_node->word = (char*) malloc(strlen(word)+1); strcpy(new_node->word, word); if (!line) { line = new_node; } else { for(current=line; current->next; current = current->next); current->next = new_node; } return line; } Node* read_line(void) { Node* line = NULL; char c, *word = NULL; unsigned i; while (1) { c = getchar(); i = 1; while (c != ' ' && c != '\n') { word = (char*) realloc(word, i*sizeof(char)); ALLOCCHECK(word); *(word+i-1) = c; i++; c = getchar(); } word = (char*) realloc(word, i*sizeof(char)); ALLOCCHECK(word); *(word+i-1) = '\0'; line = add_to_list(line, word); free(word); word = NULL; if ( c == '\n') break; } return line; } void print_list(Node* list) { Node* current = list; while (current) { printf("%s\n", current->word); current = current->next; } } int main(void) { Node* line = NULL; line = read_line(); print_list(line); free(line); line = NULL; return 0; } |
8.8.2017, 13:26 | #2 |
V.I.P. GNU/Linux
Član od: 1.11.2005.
Poruke: 11.222
Zahvalnice: 2.134
Zahvaljeno 4.961 puta na 2.887 poruka
|
Re: C program i curenje memorije
Nemam pojma, ali imam par saveta za optimizaciju:
1. Formiranje stringa tako što čitaš znak po znak i svaki put radiš realokaciju bafera je nepotrebno drndanje memorijskog alokatora operativnog sistema i teoretski može izazvati veliku fragmentaciju memorije procesa (ne u ovom slučaju pošto je trivijalan program, ali u nekom visoko threadovanom programu koji ovo radi jako brzo, može i te kako). Realloc nije predviđen za takve namene. Prosto učitaj string sa gets() koji kopira string sa ulaza dok ne pritisneš \n, dobićeš pointer na učitani string, eventualno možeš nad njim da proveriš da li sadrži razmake i da na lokaciji razmaka staviš NULL karakter da bi ga terminisao. Pošto gets() vraća adresu, prosto je prekopiraj u node->word. 2. Preradi program tako da element liste ne sadrži pointer na bafer, nego da je bafer u samom elementu, to jest: typedef struct node { char word[MAX_SIZE]; struct node* next; } Node; i izbaci alokacije worda pa vidi je l se valgrind i dalje žali. String koji učitaš sa gets možeš prosto da iskopiraš u word. |
8.8.2017, 16:27 | #3 |
Član
Član od: 13.3.2017.
Poruke: 55
Zahvalnice: 30
Zahvaljeno 3 puta na 3 poruka
|
Re: C program i curenje memorije
Ovako radi potpuno korektno, ali u postavci zadatka moram da čuvam dinamički alociranu memoriju u listi. Probaću da iskoristim ovaj način učitavanja sa fgets(), i nekako da dinamički alociram prostor za svaku reč.
Kod:
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> #define LENGHT 81 #define ALLOCCHECK(x) if ((x) == NULL) exit(-2) typedef struct node { char word[LENGHT]; struct node* next; } Node; void delete_list(Node* list) { Node* old; while(list) { old = list; list = list->next; free(old); } } Node* add_to_list(Node* line, char* word) { Node* current; Node* new_node =(Node*) malloc(sizeof(Node)); new_node->next = NULL; strcpy(new_node->word, word); if (!line) { line = new_node; } else { for(current=line; current->next; current = current->next); current->next = new_node; } return line; } Node* read_line(void) { Node* line = NULL; char input[LENGHT+1], word[LENGHT], *c; unsigned i; if (fgets(input, LENGHT-1, stdin) == NULL) exit(-2); c = input; while (1) { i = 0; while (*c != ' ' && *c != '\n') { word[i++] = *c; c++; } word[i] = '\0'; line = add_to_list(line, word); if (*c != '\n') { c++; } else { break; } } return line; } void print_list(Node* list) { Node* current = list; while (current) { printf("%s\n", current->word); current = current->next; } } int main(void) { Node* line = NULL; line = read_line(); print_list(line); free(line); line = NULL; return 0; } Kod:
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> #define LENGHT 81 #define ALLOCCHECK(x) if ((x) == NULL) exit(-2) typedef struct node { char *word; struct node* next; } Node; void delete_list(Node* list) { Node* old; while(list) { old = list; list = list->next; free(list->word); free(old); } } Node* add_to_list(Node* line, char* word) { Node* current; Node* new_node =(Node*) malloc(sizeof(Node)); new_node->next = NULL; new_node->word = malloc(strlen(word)+1); ALLOCCHECK(new_node->word); strcpy(new_node->word, word); if (!line) { line = new_node; } else { for(current=line; current->next; current = current->next); current->next = new_node; } return line; } Node* read_line(void) { Node* line = NULL; char input[LENGHT+1], word[LENGHT], *c; unsigned i; if (fgets(input, LENGHT-1, stdin) == NULL) exit(-2); c = input; while (1) { i = 0; while (*c != ' ' && *c != '\n') { word[i++] = *c; c++; } word[i] = '\0'; line = add_to_list(line, word); if (*c != '\n') { c++; } else { break; } } return line; } void print_list(Node* list) { Node* current = list; while (current) { printf("%s\n", current->word); current = current->next; } } int main(void) { Node* line = NULL; line = read_line(); print_list(line); free(line); line = NULL; return 0; } |
Sledeći korisnik se zahvaljuje korisniku NovaNada na korisnoj poruci: | ||
voodoo_ (8.8.2017) |
8.8.2017, 17:08 | #4 |
V.I.P. GNU/Linux
Član od: 1.11.2005.
Poruke: 11.222
Zahvalnice: 2.134
Zahvaljeno 4.961 puta na 2.887 poruka
|
Re: C program i curenje memorije
Alternativno, ako baš nećeš da budeš ograničen maksimalnom mogućom dužinom stringa, možeš da pokušaš sa prvobitnom implementacijom koristeći realloc(), ali da ne pozivaš realokaciju nakon svakog učitanog znaka već da alociraš word na neku fiksnu dužinu (npr. LENGTH), i tek ako probije tu dužinu tokom učitavanja, onda uradiš realloc na 'i' * LENGTH (gde je 'i' inicijalno jedan i povećava se pred svaku novu realokaciju). U tipičnoj upotrebi programa, realloc nikad neće ni biti pozvan, a formalno si podržao stringove beskonačne dužine (teoretski).
Sličan princip koristi implementacija vektora (niza) u standardnoj biblioteci C++, gde imaš fleksibilan niz proizvoljne dužine, a ispod haube se radi realokacija po potrebi i u velikim koracima (da bi se izbegla fragmentacija memorije). |
Sledeći korisnik se zahvaljuje korisniku voodoo_ na korisnoj poruci: | ||
NovaNada (8.8.2017) |
8.8.2017, 17:31 | #5 |
Član
Član od: 13.3.2017.
Poruke: 55
Zahvalnice: 30
Zahvaljeno 3 puta na 3 poruka
|
Re: C program i curenje memorije
Uradiću i na taj način.
Sada sam implementirao sličan program, samo što reči stavlja u dinamički niz, tj. matricu. Valgrind kaže da je sve dobro, ali meni se ne sviđa rešenje jer nikada nisam video da iko koristi char***. Da li može drugačije da se uradi? Kod:
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> #define LENGHT 81 #define ALLOCCHECK(x) if ((x) == NULL) exit(-2) char** add_to_matrix(char** m, char *word, int *n); void read_line(char*** m, int *n) { char input[LENGHT+1], word[LENGHT], *c; unsigned i; if (fgets(input, LENGHT-1, stdin) == NULL) exit(-2); c = input; while (1) { i = 0; while (*c != ' ' && *c != '\n') { word[i++] = *c; c++; } word[i] = '\0'; *m = add_to_matrix(*m, word, n); if (*c != '\n') { c++; } else { break; } } } char** add_to_matrix(char** m, char *word, int *n) { if (m != NULL) { m = realloc(m, (*n+1)*sizeof(char*)); ALLOCCHECK(m); *(m + *n) = malloc(sizeof(word)+1); strcpy(*(m + *n), word); (*n)++; } else { m = malloc(sizeof(char*)); ALLOCCHECK(m); *m = malloc(sizeof(word)+1); ALLOCCHECK(*m); strcpy(*m, word); (*n)++; } return m; } int main(void) { int n = 0; /*broj elemenata u matrici*/ char** m = NULL; /*matrica*/ read_line(&m, &n); for (int i = 0; i<n; i++) { printf("%s\n", *(m+i)); free(*(m+i)); } free(m); return 0; } |
Bookmarks sajtovi |
Alatke vezane za temu | |
Vrste prikaza | |
|
|
Slične teme | ||||
tema | temu započeo | forum | Odgovora | Poslednja poruka |
Program za merenje brzine protoka | boskoc | Aplikativni softver | 9 | 7.2.2010 18:23 |
Jednostavan program za melodije | Schnak3 | Audio softver | 9 | 15.11.2009 1:38 |
Asus P5Q Pro kompatibilne i nekompatibilne memorije | ivanza | Osnovne komponente | 4 | 13.12.2008 16:43 |
Toshiba A100 ne vidi 1GB memorije | Marti Misterija | Prenosni računari | 9 | 4.9.2008 21:05 |
Overclock DDR memorije! | sasha vukelic | Overklok | 13 | 28.12.2005 16:11 |