Forum Sveta kompjutera

Nazad   Forum Sveta kompjutera > Test Run > Programiranje

Programiranje Programski jezici, tehnike, alatke...

Odgovor
 
Alatke vezane za temu Vrste prikaza
Stara 7.8.2017, 18:31   #1
NovaNada
Član
 
Član od: 13.3.2017.
Poruke: 55
Zahvalnice: 30
Zahvaljeno 3 puta na 3 poruka
Određen forumom 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;
}
NovaNada je offline   Odgovor sa citatom ove poruke
Stara 8.8.2017, 13:26   #2
voodoo_
V.I.P. GNU/Linux
 
Avatar korisnika voodoo_
 
Član od: 1.11.2005.
Poruke: 11.163
Zahvalnice: 2.081
Zahvaljeno 4.922 puta na 2.858 poruka
Određen forumom 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.
voodoo_ je offline   Odgovor sa citatom ove poruke
Stara 8.8.2017, 16:27   #3
NovaNada
Član
 
Član od: 13.3.2017.
Poruke: 55
Zahvalnice: 30
Zahvaljeno 3 puta na 3 poruka
Određen forumom 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;
}
EDIT: Uspeo sam, Valgrind više ne kuka. Hvala Voodoo!
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;
}
NovaNada je offline   Odgovor sa citatom ove poruke
Sledeći korisnik se zahvaljuje korisniku NovaNada na korisnoj poruci:
voodoo_ (8.8.2017)
Stara 8.8.2017, 17:08   #4
voodoo_
V.I.P. GNU/Linux
 
Avatar korisnika voodoo_
 
Član od: 1.11.2005.
Poruke: 11.163
Zahvalnice: 2.081
Zahvaljeno 4.922 puta na 2.858 poruka
Određen forumom 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).
voodoo_ je offline   Odgovor sa citatom ove poruke
Sledeći korisnik se zahvaljuje korisniku voodoo_ na korisnoj poruci:
NovaNada (8.8.2017)
Stara 8.8.2017, 17:31   #5
NovaNada
Član
 
Član od: 13.3.2017.
Poruke: 55
Zahvalnice: 30
Zahvaljeno 3 puta na 3 poruka
Određen forumom 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;
}
NovaNada je offline   Odgovor sa citatom ove poruke
Odgovor

Bookmarks sajtovi

Alatke vezane za temu
Vrste prikaza

Vaš status
Ne možete postavljati teme
Ne možete odgovarati na poruke
Ne možete slati priloge uz poruke
Ne možete prepravljati svoje poruke

BB kod: uključeno
Smajliji: uključeno
[IMG] kod: uključeno
HTML kod: isključeno


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


Sva vremena su po Griniču +2 h. Sada je 19:26.


Powered by vBulletin® verzija 3.8.7
Copyright ©2000–2024, vBulletin Solutions, Inc.
Hosted by Beograd.com