odczyt pliku csv w języku C, realloc

0

napisałem funkcję do oczytywania pliku z csv, niestety program nawet nie chce zczytać mi ile mam "linijek" w pliku csv. Może ktoś podrzuci jakiś pomysł?

void odczyt (float **tab)

{
    int n,k,l,i,p,h ;
    FILE* plik ;
    plik = fopen("plik.csv","r");
    n=0 ;
    while(fgetc(plik)!=EOF)
    {
        n++ ;
    }
    printf("%d\n", n) ;
    tab = realloc(tab,n*sizeof(float)) ;
    for(i=0; i<n; i++)
        tab=realloc(tab,2*sizeof(float)) ;
    for(k=0; k<n; k++)
    {
        for(l=0; l<2; l++)
            fscanf(plik, "%f", &tab[k][l]);
    }
    fclose(plik);

}
0

Char != float
sprawdzasz liczbe znakow w pliku, czyli jak masz 200 znakow (np 20 wartosci float zapisanych w pliku), to starasz sie realokować pamięc dla 200x2 wartosci float.
Wczytaj ile masz wartosci w pliku scanfem, potem przenies wskaźnik do poczatku pliku i zrob to jak robisz.
Gdybyś chciał dowiedziec się ile masz wartosci w linice to pobierz linijke do pamieci (tutaj realoc jak znalazł), a potem przesledz go na cstringu ile jest tych wartosci.

Dla tego przypadku lepiej byłoby gdybyś zwolnił poprzednią pamięc i przydzielił ją od poczatku. Powinien wyjść Ci mniejszy nakład pracy programu.

0

A po co Ci ilość linijek podczas czytania pliku? Czytaj kolejne wartości i odpowiednio powiększaj tablicę. Jak przeczytasz cały plik, będziesz wiedział, ile masz linijek.

0

Bo to głupie realocować pamiec za każdym razem? ;)

Dodatkowo po sprawdzeniu kodu dochodzi jeszcze

tab = realloc(tab,n*sizeof(float)) ;
for(i=0; i<n; i++)
    tab=realloc(tab,2*sizeof(float)) ;

To jest calkowicie źle.

0

A można dowiedzieć się, co tu jest nie tak?

1

@Błękitny Krawiec: a kto powiedział, że każde wywołanie realloc powoduje faktyczną realokacje pamięci? U mnie na milion wywołań (dla float) wyszło około 850 realokacji pamięci. Można się spierać, czy to dużo, czy mało, ale czy to będzie wolniejsze od policzenia wszystkich linii w pliku csv z milionem pozycji? Wątpię.

0
void odczyt (float **tab)

{
    int n,k,l,i,p,h ;
    FILE* plik ;
    plik = fopen("plik.csv","r");
    n=0 ;
    while(fgetc(plik)!=EOF)
    {
        n++ ;
        tab = realloc(tab,n*sizeof(float)) ;
    for(i=0; i<n; i++)
        tab=realloc(tab,2*sizeof(float)) 
    }
    ;
    for(k=0; k<n; k++)
    {
        for(l=0; l<2; l++)
            fscanf(plik, "%f", &tab[k][l]);
    }
    fclose(plik);

}

teraz spoko?
To ma być tablica, która ma 2 kolumny i nie znaną ilość wierszy

0

Nie, nie jest spoko. Te dwie kolumny to zawsze tak będzie? Jaki jest separator (bo w plikach csv zawsze jakiś jest)?

Pętla while to jakieś nieporozumienie.

0

tak, zawsze tak będzie. Takie jest założenie. Pętle wziąłem z instrukcji do zajęć podaną przez prowadzącego. Liczę na trochę wyrozumiałości, skoro coś takiego dostałem na zajęciach.

0

Można tak:

float* p = NULL;
int n = 0;
float v1, v2;

FILE* plik = fopen("plik.csv","r");

while(fscanf(plik, "%f %f", &v1, &v2) == 2)
{
	p = (float*) realloc((void*)p, (n + 2) * sizeof(float));
	p[n] = v1;
	p[n + 1] = v2;
	n += 2;
}
	
float (*tab)[2] = (float (*)[2])p; // 'tab' to tablica 2-wymiarowa o 'n' wierszach
n /= 2;
0

Zrobiłem po swojemu

void odczyt(float **tab)
{   int k, i ;
    int n = 0;
    FILE* plik ;
    plik = fopen("plik.csv","r");
    char znak;
    while ((znak = fgetc(plik)) != EOF)
    {

        if (znak == '\n')
            ++n ;
    }
    printf("%d\n",n) ; // tu sprawdzam czy mi dobrze liczy( dobrze) . 
    tab = realloc(tab,n*sizeof(float)) ;
    for(i=0; i<n; i++)
        tab[i]=realloc(tab,2*sizeof(float)) ;
    for(k=0; k<n; k++)
    {
        fscanf(plik, "%f;%f", &tab[k][0],&tab[k][1]) ;
           fscanf(plik, "\n")    ;
    }

        fclose(plik);

}

Dalej mi jednak coś nie gra z realokacją pamięci. Rzuci ktoś okiem?

0

Masz post wyżej dobre rozwiązanie, co Ci się w nim nie podoba?

Poza tym:
Najpierw otwierasz plik i czytasz go do końca, licząc linie. A potem próbujesz dalej czytać ten plik?

0

Wszystko małymi krokami, średnio rozumiem tamten sposób postępowania, a bardzo mi zależy na tym żeby wiedzieć co jest źle w moim sposobie rozumowania. Objaśnie może :

while ((znak = fgetc(plik)) != EOF)
    {

        if (znak == '\n')
            ++n ;
    }

// tu sprawdzam jak duzo pamięci bedzie potrzeba na nowa tablice **tab taką wysyłam do funkcji.

tab = realloc(tab,n*sizeof(float)) ;
    for(i=0; i<n; i++)
        tab[i]=realloc(tab,2*sizeof(float)) ;

zależy mi na tym żeby dowiedzieć się czy dobrze realokuje pamięć a jak nie to proszę o ewentualną poprawkę.
Nie rozumiem co jest nie tak w fscanf

0

średnio rozumiem tamten sposób postępowania

Przecież tamten sposób jest prostszy niż twój. W skrócie wygląda tak:

  1. czytasz dwie wartości.
  2. powiększasz tablicę o dwa miejsca (tablica jest jednowymiarowa, jakbyś nie zauważył).
  3. wpisujesz na koniec tablicy wczytane wcześniej wartości.
  4. wracasz do punktu pierwszego (całość powtarzasz tak długo, aż przeczytasz wszystkie linie w pliku).

Prościej się nie da ;)

0

Naprawdę tak trudno na forum wrzucić poprawnie sformatowany kod?

Zamiast tak:

fscanf(plik, "%f;%f", &tab[k][0],&tab[k][1]) ;
fscanf(plik, "\n");

Może lepiej będzie tak:

fscanf(plik, "%f;%f;", &tab[k][0], &tab[k][1]);
kucia2129 napisał(a):

Nie rozumiem co jest nie tak w fscanf

Problem w tym, że próbujesz czytać z pliku, w momencie kiedy dotarłeś już na jego koniec. Więc jeśli już policzyłeś te linie w poprzedniej pętli, to przesuń się ze wskaźnikiem położenia w pliku na jego początek za pomocą instrukcji takich jak: rewind, lub fseek.

Poza tym, twój algorytm liczenia lini w pliku, zakłada, że w ostatniej linii musi znajdować się znak nowego wiersza.

0
void odczyt(float **tab)
{   int k, i ;
    int n = 0;
    FILE* plik ;
    plik = fopen("plik.csv","r");
    char znak;
    while ((znak = fgetc(plik)) != EOF)
    {

        if (znak == '\n')
            ++n ;
    }
    printf("%d\n",n) ;
    rewind(plik) ;
    tab = realloc(tab,n*sizeof(float)) ;
    for(i=0; i<n; i++)
        tab[i]=realloc(tab,2*sizeof(float)) ;
        rewind(plik) ;
    for(k=0; k<n; k++)
    {
        fscanf(plik, "%f;%f;", &tab[k][0],&tab[k][1]) ;
    }

        fclose(plik);

}

chyba włożyłem tam wszystko co mówiliście. Ale kurde program się wysypuje. Gdzieś jeszcze mam błąd. Strzelam, że z alokacją pamięci

0

Jeśli tab ma być tablicą wskaźników, to tak powinno być:

tab = realloc(tab, n * sizeof(float*)) ;
for(i=0; i<n; i++)
      tab[i]=realloc(tab,2*sizeof(float)) ;

Ojojoj. Coś Ty się tak na tego realloca uparł? Użyj tutaj funkcji malloc... choć w sumie wszędzie użyj, bo w twoim kodzie nie ma zastosowania dla realloc.

0

Założenie projektowe na zajęcia :D Program ma odczytywać plik csv a potem go jeszcze filtrować.

No dalej nie działa :/

void odczyt(float **tab)
{
    int k, i ;
    int n = 0;
    FILE* plik ;
    plik = fopen("plik.csv","r");
    char znak;
    while ((znak = fgetc(plik)) != EOF)
    {
        if (znak == '\n')
            ++n ;
    }
    printf("%d\n",n) ;
    tab = realloc(tab, n * sizeof(float*)) ;
    for(i=0; i<n; i++)
        tab[i]=realloc(tab,2*sizeof(float)) ;
    rewind(plik);
    for(k=0; k<n; k++)
        fscanf(plik, "%f;%f;", &tab[k][0],&tab[k][1]) ;
    fclose(plik);

}

Może problem jest w tym jak wyglądała ta tablica przed realokacją w main :

int main()

float **xx;
.
.
.
 xx=malloc (sizeof (float*)*1);
            for ( a = 0;a <1;a++)
        xx [i] = malloc (sizeof (float)*2)   ;
            odczyt(xx);
            free(xx) ;

Zadaniu chodziło o to, żeby nauczyć się realokować miejsce. Słabo bo idzie mi to opornie. Najpierw robie sobie tablice o dwóch kolumnach i jednym wierszu a potem ją tylko "rozciągam" . :/
Pytanie, czy mogę w main dać i pozbyć się tej alokacji?
float **xx = NULL ?

0

A pokaż cały swój kod?

A tak zapytam, jak przekazujesz informację o rozmiarze alokowanej tablicy do pozostałej części programu?
Poza tym wydaje mi się, że twoja funkcja nie będzie działać, bo na co wskazuje wskaźnik przy przekazaniu do funkcji?

Przerobiłem twój kod w taki sposób:

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

float **read(size_t *size);

int main(int argc, char *argv[]) {
  size_t size = 0;

  float **arr = read(&size);
  assert(arr != NULL && "Wrong array initialisation!");
  
  for (size_t i = 0; i < size; ++i) {
    printf("%f : %f\n", arr[i][0], arr[i][1]);
  }

  for (size_t i = 0; i < size; ++i) {
    free(arr[i]);
  }
  free(arr); 

  return EXIT_SUCCESS;
}

float **read(size_t *size) {
  float **arr = NULL;

  FILE *file = fopen("data.csv", "r");

  if (file != NULL) {
    int c;
    while((c = fgetc(file)) != EOF) {
      if (c == '\n')
        (*size)++;
    }
    rewind(file);

    arr = realloc(arr, *size * sizeof(float*));
    for (size_t i = 0; i < *size; ++i)
       arr[i] = realloc(arr[i], 2 * sizeof(float));

    c = 2;
    for (size_t i = 0; i < *size && c == 2; ++i) {
      c = fscanf(file, "%f;%f;", &arr[i][0], &arr[i][1]); 
    }
    fclose(file);
  } else {
    fprintf(stderr, "Can't open data.csv file.\n");
  }
  return arr;
}

Nie testowałem go zbyt dobrze, ale sprawia wrażenie, że działa.

0
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
void menu()
{
    puts("1. wczytaj dane poczatkowe dla M elementów.") ;

    puts("2. Czyszczenie ekranu.");

    puts("3. odczyt z csv") ;

    puts("4. Zamknij program.");


}
void skan(int M, float *f, float *phi, float *A)
{
    int i ;
    for(i=0; i<M; i++)
    {
        printf(" numer skladowych sinusoidalnych: %d ", i+1) ;

        puts("") ;

        printf("podaj %d czestotliwosc: ",i+1) ;

        scanf("%f", &f[i]) ;

        printf("podaj %d przesuniecie fazowe: ",i+1) ;

        scanf("%f", &phi[i]) ;

        printf("podaj %d amplitude: ",i+1) ;

        scanf("%f", &A[i]) ;

        puts("") ;
    }
}

void X(float tp, float m, float *A, float *f, float *phi, float **x, int M, float W)
{
    int i,j,k,a ;
    float P=0;
    for(i=0; i<W; i++)
        x[i][0]= tp+i*m ;
    for(j=0; j<W; j++)
    {
        for(k=0; k<M ; k++)
            P=(A[k]*(sin(f[k]*x[j][0]+phi[k]))) + P ;
        x[j][1] = P ;
    }

    P = 0;

}


float maximum(float *f1, int M)
{
    int i ;
    float p ;
    for ( i=0; i<(M-1); i++)
    {
        if (f1[i]> f1[i+1] )
        {
            p=f1[i] ;
            f1[i]=f1[i+1] ;
            f1[i+1]=p ;
        }
    }
    return f1[M-1] ;
}


void drukuj(float **tablica,int p)
{
    int i,j ;
    for(i=0; i<p; i++)
    {
        for(j=0; j<2; j++)
        {
            printf("%f  ", tablica[i][j]) ;
        }

        printf("\n") ;
    }
}
void zapisuj(float p, float **x)
{
    int i,j;
    FILE *plik;
    plik=fopen("plik.csv", "w");
    for(i=0; i<p; i++)
    {

        fprintf(plik, "%f; %f", x[i][0], x[i][1]) ;
        fprintf(plik, "\n") ;
    }


    fclose(plik);
}
void odczyt(float **tab)
{
    int k, i ;
    int n = 0;
    FILE* plik ;
    plik = fopen("plik.csv","r");
    char znak;
    while ((znak = fgetc(plik)) != EOF)
    {
        if (znak == '\n')
            ++n ;
    }
    printf("%d\n",n) ;
    tab = realloc(tab, n * sizeof(float*)) ;
    for(i=0; i<n; i++)
        tab[i]=realloc(tab,2*sizeof(float)) ;
    rewind(plik);
    for(k=0; k<n; k++)
        fscanf(plik, "%f;%f;", &tab[k][0],&tab[k][1]) ;
    fclose(plik);

}
int main()
{
    float to,tf,g,m,p ;
    int i,M,y,a ;
    float *phi ;
    float *f ;
    float *A ;
    float **x ;
    float **xx = NULL ;
    do
    {
        menu();
        printf("Wybierz co chcesz zrobic\n:");
        scanf("%d", &y);
        switch (y)
        {

        case 1 :
            printf("podaj  czas poczatkowy:\n ") ;
            scanf("%f", &to) ;
            printf("podaj  czas koncowy:\n") ;
            scanf("%f", &tf) ;
            M=2 ;
            phi=malloc(M*sizeof(float));
            A=malloc(M*sizeof(float));
            f=malloc(M*sizeof(float)) ;
            skan(M,f,phi,A) ;
            g=maximum(f, M) ;
            m=1/(2*g) ;
            p = (tf-to)/m ;
            printf("ILOSC POMIAROW TO:%f\n", p) ;
            x =malloc(p*sizeof(float*));
            for (i=0; i<p; i++)
            {
                x[i] =(float*) malloc(2*sizeof(float));
            }
            X(to,m,A,f,phi,x,M,p) ;
            drukuj(x,p) ;
            zapisuj(p,x) ;
            free(x) ;
            break ;
        case 2:
            system("CLS");
            break;
        case 3 :
            /* xx=malloc (sizeof (float*)*1);
             for ( a = 0;a <1;a++)
            xx [i] = malloc (sizeof (float)*2)   ;
            */
            odczyt(xx);
            free(xx) ;
            break ;
        case 4:
            return 0;
        default:
            printf("Wybierz liczbe od 1 do 4\n");
        }
    }

    while (y > 0 && y < 5);

    system("PAUSE");
    return 0 ;
}

Nie jestem na studiach informatycznych, więc nie najlepiej programuje, to dopiero mój drugi semestr z jezykiem C. Zdaje sobie sprawę, że jest źle zoptymalizowany, zformatowany, no ale całość działa, najgorzej jest w ''case 3'' Gdzie zaczynam odczytywać pliki z dysku, wtedy program przestaje odpowiadać. :(

0

http://ideone.com/JpHCAT

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

typedef struct 
{
    int count;
	int reserved;
    double *tab;
} FloatVector;

FloatVector *FloatVectorCreate(int reserve)
{
	FloatVector *result = (FloatVector *)malloc(sizeof(FloatVector));
	if (result)
	{
		result->tab = (double *)malloc(sizeof(*result->tab) * reserve);
		result->count = 0;
		result->reserved = reserve;
	}
	return result;
}

void FloatVectorFree(FloatVector *vec)
{
	if (vec)
	{
		free(vec->tab);
		free(vec);
	}
}

void FloatVectorAppend(FloatVector *vec, double x)
{
	if (vec->count >= vec->reserved)
	{
		vec->reserved += 0x10;
		vec->tab = realloc(vec->tab, sizeof(*vec->tab) * vec->reserved);
	}
	vec->tab[vec->count++] = x;
}

FloatVector *FloatVectorCreateFormString(const char *line)
{
	FloatVector *vec = FloatVectorCreate(0x10);
	char *p = (char *)line;
	while (1)
	{
		char *q = p;
		double x = strtod(q, &p);
		if (p == q)
			break;
		FloatVectorAppend(vec, x);
	}
	return vec;
}

int ReadCSV(FILE* f, FloatVector ***data)
{
	char buffer[0x800];
	int reservedDataSize = 0x10;
	int dataSize = 0;

	*data = calloc(reservedDataSize, sizeof(FloatVector *));

	while (fgets(buffer, sizeof(buffer), f))
	{
		if (dataSize >= reservedDataSize)
		{
			reservedDataSize += 0x10;
			*data = (FloatVector **)realloc(*data, reservedDataSize * sizeof(FloatVector *));
		}
		(*data)[dataSize++] = FloatVectorCreateFormString(buffer);
	}
	return dataSize;
}

int main(void) {
	FloatVector **data;

	int size = ReadCSV(stdin, &data);

	for (int i=0; i<size; ++i)
	{
		printf("%d\n", data[i]->count);
		for (int j=0; j<data[i]->count; ++j)
			printf(" %4lg", data[i]->tab[j]);
		printf("\n");
	}

	for (int i=0; i<size; ++i)
	{
		FloatVectorFree(data[i]);
	}
	free(data);
	return 0;
}
0
     while ((znak = fgetc(plik)) != EOF)
    {

        if (znak == '\n')
            ++n ;
    }
    printf("%d\n",n) ;
    rewind(plik) ;
    tab = realloc(tab,n*sizeof(float)) ;
    for(i=0; i<n; i++)
        tab[i]=realloc(tab,2*sizeof(float)) ;
        rewind(plik) ;

Twój kod określa liczbę elementów na podstawie ilości znaków. Linijka z whilem.
W pliku zapewne masz wartości zapisane jako string, czyli dla przykładu: 23,45 ile tutaj jest liczb float:1? A ile jest tutaj znaków:5? Potem tego n używasz do alokowania pamięci. Błędów jest znacznie więcej.

1 użytkowników online, w tym zalogowanych: 0, gości: 1