Listy jednokierunkowe i wczytywanie z pliku

0

Witam wszystkich, jest mi ktoś w stanie jakoś logicznie wyjaśnić jak się poruszać po listach?
Mam za zadanie napisać program do obsługi muzeum i przede wszystkim problem mam z wczytywaniem danych z pliku do listy(w pliku każda linijka oznacza inną daną eksponatu a linijka zawierająca sam średnik oznacza przejście do następnego eksponatu). Stworzyłem coś takiego i wygląda na to że w czasie wczytywania działa poprawnie :

typedef struct skladnik_t {
    struct skladnik_t *next;
    const char *LP;
    const char *nazwa_p;
    const char *opis_p;
    const char *okr_poch;
    const char *waga_p;
    const char *data_dod;
    const char *stan_p;
    const char *dost;
} skladnik;

skladnik *skladnik_stworz() {
    return malloc(sizeof(skladnik));
}




int main()
{
	int wyb, i, licz = 0, nr_l = 1, x = 1, nr_eksp = 1;
	skladnik *pocz_eksp = skladnik_stworz();
	skladnik *eksponat = pocz_eksp;
	
	FILE *ekspo;
	ekspo = fopen("eksponaty.txt","a+");
	char bufor[255];
	while(fgets ( bufor , 255 , ekspo ) != NULL)
	{
		printf("Czytam linie nr %d -> ", nr_l);
		nr_l++;
		if(eksponat->next != NULL)
		{
			if(bufor[0] == ';')
			{
				eksponat->next = skladnik_stworz();
				eksponat = eksponat->next;
				printf("Przejscie do kolejnego eksponatu..\n");
			}
			else 
			{
				switch(x)
				{
					case 1:
						eksponat->LP = bufor;
						printf("LP : %s", eksponat->LP);
						x++;
						break;
					
					case 2:
						eksponat->nazwa_p = bufor;
						printf("Nazwa %d eksponatu : %s",nr_eksp,eksponat->nazwa_p);
						x++;
						break;
						
					case 3:
						eksponat->opis_p = bufor;
						printf("Opis %d eksp : %s",nr_eksp, eksponat->opis_p);
						x++;
						break;
					case 4:
						eksponat->okr_poch = bufor;
						printf("Okres pochodzenia eksponatu nr %d : %s ", nr_eksp,eksponat->okr_poch);
						x++;
						break;
					case 5:
						eksponat->waga_p=bufor;
						printf("Waga eksp nr %d : %s",nr_eksp,eksponat->waga_p);
						x++;
						break;
					case 6:
						eksponat->data_dod = bufor;
						printf("Data dodania eks nr %d : %s",nr_eksp, eksponat->data_dod);
						x++;
						break;
					case 7:
						eksponat->stan_p = bufor;
						printf("Stan przedmiotu nr %d to %s ",nr_eksp, eksponat->stan_p);
						x++;
						break;
					case 8:
						eksponat->dost = bufor;
						if(bufor[0] == '1')
						{
							printf("Eksponat dostepny\n");
						}
						else printf("Eksponat niedostepny\n");
						x = 1;
						nr_eksp++;
						break;
				}
			}
		}
		
	}

Lecz gdy wywołuję np

printf("%s\n", eksponat->nazwa_p);

To wynikiem jest 0 wyświetlone na ekranie.
Dlaczego tak się dzieje? Co tu jest nie tak? Będę wdzięczny za każdą pomoc.

2

Po pierwsze, to nie jest to czytelne gdy wszystko siedzi w main()
Po drugie skladnik_stworz() to zmarnowana okazja, by to tworzenie zrobić naprawdę dobrze (z czyszczeniem struktury - malloc nie czyści, z gospodarką korzeniem listy itd).
Po drugie i pół, o ile nie jestem ortodoksyjnym przeciwnikiem polskich identyfikatorów, to polski identyfikator w angielskiej gramatyce jest horrorem

0

@AnyKtokolwiek: Jak na razie wszystko jest wrzucone w main'a ze względu na to że to tylko desperackie próby ogarnięcia tego.
Jestem świadom że należy jeszcze uwolnić pamięć na końcu ale zapomniałem tego dopisać

0
ShaoMean napisał(a):

@AnyKtokolwiek: Jak na razie wszystko jest wrzucone w main'a ze względu na to że to tylko desperackie próby ogarnięcia tego.

Jestem świadom że należy jeszcze uwolnić pamięć na końcu ale zapomniałem tego dopisać

Wierzysz, że jedynie uwalniania pamięci brakuje?

Nie gra prawie nic.

  • Np pod wszystkie wskaźniki podstawiasz adres tego samego bufora. Być może strdup() ma ci coś dobrego do powiedzenia. I cóż, zwalnianie pamięci się MOCNO skomplikuje.
  • algorytm tego typu jest nieprawdopodobne aby działał, bez zapewnienia czystości zmiennych (czyli ich czyszczenie przed użyciem)
  • pytasz "jest mi ktoś w stanie jakoś logicznie wyjaśnić jak się poruszać po listach" a masz braki w podstawach C. Pytasz o dach, a ledwo fundamenty wyszły z gruntu.
  • źle dobrane typy do niektórych pól tej struktury.
  • nawet nie mam zamiaru szukać Ci błędów. Wypisałem przypadkowe, które nawet o drugiej w nocy są rażące.
0

@AnyKtokolwiek: Nie mówię że to jedyne czego brakuje, być może tylko tego jestem świadom.
No cóż, gdybym nie miał braków w wiedzy to raczej nie przyszedłbym tutaj prosić o pomoc.
Jeśli pomoc w całym kodzie to zbyt wiele to proszę tylko o wyjaśnienie w prosty sposób operowania na listach, a przede wszystkim takich podstaw jak tworzenie listy, elementów do niej i przechodzenia po niej.

0

Skorzystałeś z już danych wskazówek? — AnyKtokolwiek 29 minut temu

Szczerze mówiąc nie wiele mi one mówią, jeśli chodzi o typy danych w strukturze to celowo dałem wszędzie const char* bo w wypadku np int nie wczytywało mi poprawnie danych z pliku. — ShaoMean 15 minut temu

No właśnie, nawet nie umiesz złapać koła ratunkowego. jest jakoś tragicznie trudno znaleźć specyfikację funkcji strdup, albo ulepszyć (jedyną) funkcję?

A w/w wybór mi przypomina: Milicjant spisywał protokół ze śmiertelnego wypadku. Lewa noga na jezdni, prawa noga na jezdni, lewa ręka na jezdni, prawa ręka na trotu, na trut, na tretu ... kopnął denata i pisze prawa ręka też na jezdni"

0

Ze strdup() - a jest w zasadzie konieczne - podnosi się trudność prawidłowego ZWALNIANIA struktury, pewnie pojawi się do tego funkcja.
Ale ona nie będzie działać a nawet crashować program (inne algorytmy też) jeśli struktura będzie wypełniona przypadkowymi syfkami ... itd itd

0

@AnyKtokolwiek: Mógłbyś zweryfikować poprawność mojej listy oraz czy poprawnie się do niej odwołuję? Już nie chodzi o funkcjonalność kodu tylko samą metodę, chciałbym mieć pewność że chociaż to mam zrobione poprawnie a resztę algorytmu spróbuję opracować sam

0
ShaoMean napisał(a):

@AnyKtokolwiek: Mógłbyś zweryfikować poprawność mojej listy oraz czy poprawnie się do niej odwołuję? Już nie chodzi o funkcjonalność kodu tylko samą metodę, chciałbym mieć pewność że chociaż to mam zrobione poprawnie a resztę algorytmu spróbuję opracować sam

Operację typu listowego masz dwulinijkową, Coś się niby robi i NIC tego nie weryfikuje. Zawsze można dopasować teorię do praktyki i bronić że "tak miało być".

Intencje autora są niemożliwe do określenia (kłaniają się nieoptymalne nazwy zmiennych).
Nie wynika, gdzie chcesz do listy dodawać (na początek / koniec). Nic nie wynika, a jeszcze zalane stadem błędów

Program w tym stanie nie pozwala na podobną ocenę operacji listwowych. Jako CAŁY jest ... mało wartościowy

0

Dodawać chcę na koniec, mówi o tym wczytanie średnika z pliku, jeśli jest średnik to tworzy się kolejny element listy i automatycznie przechodzi do tego elementu żeby dalej wczytywać dane do kolejnego elementu. W takim razie nie będę się bronił, wiem że kod jest bezużyteczny ale chciałbym wiedzieć czy sama struktura "składnik" wraz funkcją do alokowania pamięci ma prawo działać? Jeśli tak to jak poprawnie utworzyć kolejny element i do niego przejść? Tak żeby wszystkie dane były dostępne i funkcjonalne? — ShaoMean 1 minuta temu

o tej funkcji już pisałem. Jak napiszę dwa razy, będzie ważniejsze?

Dla ciebie rada: DZIEL problemy (i rządź).
średnik nie ma nic do operacji listowych sensu stricte . To jest coś odrębnego, dotyczy budowy pliku wejściowego, ale nie samej listy
To jest właśnie patologia pisania całego rozwiązania w main(), źle nakierowuje myślenie na "all in one"

Ja ci nie będę radził, co masz zrobić w etapie D albo E, jeśli nie tknąłeś porad A,B,C. Tłumów innych doradzajacych nie widać.

0

@AnyKtokolwiek: Mógłbyś proszę sprawdzić te funkcje? zacząłem pisanie od nowa z pełną mobilizacją żeby było poprawnie


typedef struct node_t {
    struct node_t *next;
    const char *item_name;
    const char *desc;
    const char *period_of_origin;
    float weight;
    const char *add_date;
    int item_condition;
    bool avalibility;
} node;

typedef struct list_t{
	int size;
	node *first;
} list;

node *create_node() {
    return malloc(sizeof(node));
}

void list_init(list *list)
{
	list->size=0;
	list->first=NULL;
}

int list_insert(list *list, node data)
{
	node *TMP = NULL; 
	node *End = NULL;
	node *New = NULL;
	
	TMP = list->first;
	End = list->first;
	
	while(TMP)
	{
		End = TMP; 									//zapamietanie poprzedniego wezla
		TMP = TMP->next; 							//przejscie do nast wezla
	}
	
	if(TMP)
		return -1 									//nie udalo sie dostac na koniec listy
		
	New = (node*)malloc(sizeof(node));				//stworzenie nowego wezla
	if(!New)
		return -3; 									//nie udalo sie zaalokowac pamieci
		
	New->next = NULL; 								//nowy wezel staje sie ostatnim
	New->item_name = data->item_name;
	New->desc = data->desc;
	New->period_of_origin = data->period_of_origin;	//uzupelnianie danych nowego wezla
	New->weight = data->weight;
	New->add_date = data->add_date;
	New->item_condition = data->item_condition;
	New->avalibility = data->avalibility;
	++(list->size);									//zwieksza ilosc elementow listy
	if(!End) 										//lista nie ma konca
	{
		list->first = New;
		return 0;
	}
	
	End->next = New;								//dodanie elementu na koniec listy
	return 0;
}

Jeszcze tylko muszę stworzyć funkcje która usuwa listę lub wybrany element

2

Wydzielenie struktury na uchwyt listy mi się podoba, miałem to zaproponować w etapie E :)

Zrobiłeś funkcje do alokowania tym razem nazywającą się create_node (która dalej nie czyści), ale to nic 1) bo i tak jej nie używasz.
itd itp
F. create_node ja bym sobie wyobrażał w odniesieniu już do listy ()w nie w powietrzu), ale ja nie jestem ty. To by zaspokajało moje myślenie obiektowe (tak, w C można myśleć obiektowo).

Funkcja list_insert dokonuje karkołomnych rzeczy, tylko dlatego, ze argument ma podany przez wartość.
To nie jest C++, ale tamtejszy sposob myśenia spróbujmy zastosować (choć idealnie się nie da). Niech funkcje operujace na liście udają, ze nie wiedzą, jakie są pola w node - a te, które walczą z polami, niech nie dokonują operacji listowych (w miarę możliwości)

  1. scena z Barei, chłoporobotnik opowiada, że zawsze spóźnia się na autobus robotniczy o 4 rano "ale to nic, on i tak sie nie zatrzymuje, bo przepełniony"
0

@AnyKtokolwiek: Moja radość nie trwała zbyt długo, zmieniłem poprzednie create_node na coś takiego:

node *create_node() {
	node node = malloc(sizeof(node));
	node->avalibility = NULL;
	node->add_date = NULL;
	node->desc = NULL;
	node->item_condition = NULL;
	node->item_name = NULL;
	node->next = NULL;
	node->period_of_origin = NULL;
	node->weight = NULL;
    return node;
}

I teraz kompilator wyrzuca "[Error] invalid initializer" przy

node node = malloc(sizeof(node));

oraz "[Error] expected identifier or '(' before '->' token" przy każdej kolejnej linii tej funkcji
To znaczy że nie mogę wykorzystać struktury node w tej funkcji?

0

Zacznij od definicji prostych rzeczy:

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

#define AsStr(x) #x
#define ToStr(x) AsStr(x)
#define ScanFormat(x) " %" ToStr(x) "[^\n]"

#define name_max_length 48
#define supplier_max_length 64

const char name_format[]=ScanFormat(name_max_length);
const char supplier_format[]=ScanFormat(supplier_max_length);

typedef struct item_t
{
    struct item_t *next;
    char name[name_max_length+1];
    double weight;
    char supplier[supplier_max_length+1];
} item;

typedef struct list_t
{
    item *head,*tail;	
} list;

void add(list *lst,item *src)
{
	item *data=(item*)malloc(sizeof(item));
	memcpy(data,src,sizeof(item));
	data->next=NULL;
	if(lst->tail) lst->tail->next=data;
	else lst->head=data;
	lst->tail=data;
}

item *scan(FILE *in,item *src)
{
	if(in==stdin) printf("Name: ");
	scanf(name_format,src->name);
	if(in==stdin) printf("Waga: ");
	scanf(" %f",&src->weight);
	if(in==stdin) printf("Dostawca: ");
	scanf(name_format,src->supplier);
	return src;
}

void print_item(int lp,item *src)
{
	printf("LP: %d\n",lp);
	printf("Name: %s\n",src->name);
	printf("Waga: %.3lf\n",src->weight);
	printf("Dostawca: %s\n",src->supplier);
}

void print_list(list *lst)
{
	int lp=0;
	for(item *i=lst->head;i;i=i->next,printf("\n")) print_item(++lp,i);
}

void free_list(list *lst)
{
	for(item *next=NULL,*i=lst->head;i;i=next)
	{
		print_item(0,i);
		next=i->next;
		free(i);
	}
	lst->head=lst->tail=0;
}

int main()
{
	list lst={NULL,NULL};
	item data;
	for(int i=0;i<3;++i,printf("\n"))
	{
		printf("Record %d/3:\n",i+1);
		add(&lst,scan(stdin,&data));
	}
	print_list(&lst);
	printf("free:\n");
	free_list(&lst);
	return 0;
}

Dalej sobie stopniowo rozwijasz.

0

@_13th_Dragon @AnyKtokolwiek
Istnieje może jakiś magiczny sposób żeby odczytywać z pliku znaki/wyrazy aż do danego znaku (np. średnika)?
Nie mogę się uporać z wczytywaniem danych które zawierają znaki białe typu spacja

2

scanf("%99[^;]",line);
getline(cin,line,';')

0

@_13th_Dragon @AnyKtokolwiek

Teraz mam problem przy uruchomieniu debuggerem, wyskakuje mi bląd : Nieobsłużony wyjątek w lokalizacji 0x5469FF5C (ucrtbased.dll) w Project1.exe: 0xC0000005: Naruszenie zasad dostępu podczas odczytywania w lokalizacji 0x00000031.

Przy funkcji

const char* get_line(FILE* input)
{
	char buffer[100];
	fscanf(input,"%99[^;]", &buffer);
	return *buffer;
}

node* create_data(FILE* input)
{
	int i;
	node *data = create_node();
	const char* eptr;
	for (i = 0; i < 8; i++)
	{
		const char *buffer2 = malloc(sizeof(const char));
//		buffer = get_line(input);
		buffer2 = strdup(get_line(input));
		switch (i)
		{
			case 0:
				data->ID = atoi(buffer2);
				break;
			case 1:
				data->item_name = buffer2;
				break;
			case 2:
				data->desc = buffer2;
				break;
			case 3:
				data->period_of_origin = buffer2;
				break;
			case 4:
				data->weight = strtod(buffer2, &eptr);
				break;
			case 5:
				data->add_date = buffer2;
				break;
			case 6:
				data->item_condition = atoi(buffer2);
				break;
			case 7:
				data->avalibility = atoi(buffer2);
				break;
		}

	}
	return data;
}

a dokładniej osob "buffer = get_line(input)"

0

@ShaoMean:

Gdzieś jest użyty wskażnik null

Albo źle napisana funkcja get_line - zwraca adres wewnętzrnego bufora, który za mikrosekundę przestanie istnieć
Akurat zwykle dodanie funkcji będzie pochwalone, ale tu jest tak prosta, ze wcale nie jest potrzebna

Tam gdzie masz dane integerowe, nie musisz strdup, mozesz robić atoi z oryginału. Robisz strdup TYLKO dla danych stringowych
Każde strdup to u ciebie wyciek pamięci. Chciałbym aby powstała funkcja void delete_node(node *)

0
const char* get_line(FILE* input)
{
    char buffer[100];
    fscanf(input,"%99[^;]", &buffer);
    return *buffer;
}

A co mówi kompilator o linijce return *buffer?

0

fscanf(input,"%99[^;]", &buffer); - mażesz po pamięci
ma być:
fscanf(input,"%99[^;]",buffer);

0

W sumie wg mnie powinno być:

char *get_line(FILE* input)
{
    char buffer[100];
    fscanf(input,"%99[^;]",buffer);
    return strdup(buffer); // od razu kopia.
}
0
_13th_Dragon napisał(a):

W sumie wg mnie powinno być:

char *get_line(FILE* input)
{
    char buffer[100];
    fscanf(input,"%99[^;]",buffer);
    return strdup(buffer); // od razu kopia.
}

Ogólny strdup w tym projekcie jest zbędny.
W ogóle funkcja jest jedną z najmniej potrzebnych. Co do wyodrębniania funkcji para poszła w gwizdek, są ważniejsze ku temu obszary

0

wiele funkcji w C są zbędne np strlen, przecież to jedna pętla, można napisać samemu zamiast za każdym razem wywoływać jakąś funkcję która nie wiadomo co roni. :D — _13th_Dragon 4 minuty temu

Chcesz troszeczkę ironizować.

w C moim zdaniem NAJWIĘKSZYM HARDCOREM są funkcje jak ta - wymagające wyjaśnień jakie efekty oboczne i co zrobić - czyli "zwraca bufor statyczny" (są takie standardowe) albo "zwolnij otrzymany wskaźnik" (też są), i grożące ukrytymi błędami. Nie da się tego w C w żaden sposób sformalizować.

strlen() nie wymaga jakiś przygotowań przed ani procedury po. Sam zysk.
Ta wymaga, i więcej jest tej procedury niż oszczędność mierzonej w liniach czy w klarowności - kod inline jest klarowniejszy, nie zaburzony zbędnymi procedurami - stąd głosuję na nie.
Gdybym rozmawiał na płaszczyźnie rygorystycznych nazw, funkcja by się nazywała alloc_and_get_line. A jak w nazwie funkcji jest "and", to jest ślisko

0

W nawiązaniu do postulatów @MarekR22 i @_13th_Dragon o moją wersję kodu zamieszczam te części, które są dla mnie istotne.

~const char* get_line(FILE* input)
{
char buffer[100];
fscanf(input,"%99[^;]", &buffer);
return *buffer;
}~~

w/w wylatuje bo dla "lepszego stylu" operacji jednolinijkowej powoduje wiele większy młyn

node* create_data(FILE* input)
{
    int i;
    node *data = create_node();
    const char* eptr;
    for (i = 0; i < 8; i++)
    {
        char buffer[110];
       memset(buffer,'\0',sizoef(buffer));
       fgets(buffer, sizeof(buffer)-1, input);
       buffer[ strlen(buufer)-1 ] = '\0';  // utrącenie \n
// utrącić średnik - nie pamiętam struktury pliku @ShaoMean
// lub w rodzaju if(strcmp(buffer,";") break;


        switch (i)
        {
            case 0:
                data->ID = atoi(buffer);
                break;
            case 1:
                data->item_name = strdup(buffer);
                break;
            case 2:
                data->desc = strdup(buffer);
                break;
            case 3:
                data->period_of_origin = strdup(buffer);
                break;
            case 4:
                ~ data->weight = strtod(buffer, &eptr); ~  <-- błąd, to nie ten drugi argument
                data->weight = atof(buffer);  
                break;
            case 5:
                data->add_date = strdup(buffer);
                break;
            case 6:
                data->item_condition = atoi(buffer);
                break;
            case 7:
                data->avalibility = atoi(buffer);
                break;
        }

    }
    return data;
}

void free_item(item * it)
{
   free( it->item_name );
   free( it->period_of_origin);
   free( it->add_date );
  ...
  free(it);
}
0

Funkcję get_line już usunąłem, po zastosowaniu twojej propozycji problem jest taki ze fgets() bierze całą linię, ja bym chciał żeby funkcja wczytała tekst z pliku do średnika, zapis do buffora, przypisanie elementowi listy wartości z buffora a potem dalej czytała do kolejnego średnika i tak w kółko — ShaoMean 37 minut temu

merytoryczne wypowiedzi w postach, nie w komentarzach

Czyli pewnie jakaś funkcja wróci, tylko po inną nazwą. Ona po prostu nie powinna się nazywać get_line.
W ogóle struktura liniowa tu zachodzi? Czy "liniowa" jest tylko ,linia ze średnikiem (koniec pozycji, przejście do następnej) ?
Chyba nigdzie w wątku format pliku nie był podany z pełną ścisłością???

Nie mam ani czasu, ani by nie było pedagogiczne zrobić za ciebie, pociągnij NA PRZYKŁAD ten szkielet

// @returns statyczny bufor
const char * get_atom(FILE * input)
{
    char bufeer[110];
    static char bufeer2[50];  <- na wynik
    ...
    return buffer2;
} 
2

Wszystko z tobą jasne. Zaraz będzie potrzeba wczytanie tegoż z ekranu, import/export do json itp. I wszędzie będzie taka litania case'ów?

#include <stdio.h>

#define TOSTR(value) #value
#define ASSTR(value) TOSTR(value)
#define STRFORMAT(length) " %" ASSTR(length) "[^\n]"
#define LongFORMAT " %ld"
#define IntFORMAT " %d"
#define FloatFORMAT " %f"
#define OFFSET(record,member) ((char*)&(((record*)0)->member)-(char*)0)
#define LENGTH(record,member) (sizeof(((record*)0)->member))

typedef void outproc(FILE *fd,char *ptr);

typedef struct _data_struct
{
	int offset;
	char name[32];
	char informat[16];
	outproc *out;
}data_struct;

#define item_name_len 32
#define item_desc_len 128
#define date_len 10
typedef struct _item_data
{
	long id;
	char name[item_name_len+1];
	char desc[item_desc_len+1];
	char period_of_origin[date_len+1];
	float weight;
	char add_date[date_len+1];
	int condition;
	int avalibility;
}item_data;

void showstr(FILE *fd,char *ptr) { fprintf(fd,"%s",ptr); }
void showlong(FILE *fd,char *ptr) { fprintf(fd,"%ld",*((long*)ptr)); }
void showint(FILE *fd,char *ptr) { fprintf(fd,"%d",*((int*)ptr)); }
void showfloat(FILE *fd,char *ptr) { fprintf(fd,"%f",*((float*)ptr)); }

data_struct item_data_struct[]=
{
	{OFFSET(item_data,id),"ID",LongFORMAT,&showlong},
	{OFFSET(item_data,name),"Nazwa",STRFORMAT(item_name_len),&showstr},
	{OFFSET(item_data,desc),"Opis",STRFORMAT(item_desc_len),&showstr},
	{OFFSET(item_data,weight),"Waga",FloatFORMAT,&showfloat},
	{OFFSET(item_data,add_date),"Data dostawy",STRFORMAT(date_len),&showstr},
	{OFFSET(item_data,condition),"Stan",IntFORMAT,&showint},
	{OFFSET(item_data,avalibility),"Ilosc",IntFORMAT,&showint},
	{OFFSET(item_data,period_of_origin),"Data waznosci",STRFORMAT(date_len),&showstr},
	{-1,"",""},
};

int file_read_item(FILE *fd,item_data *data,data_struct *tb)
{
	int i;
	for(i=0;tb[i].offset>=0;++i)
	{
		if(fscanf(fd,tb[i].informat,((char*)data)+tb[i].offset)!=1) return -i;
	}
	return i;
}

void show_item(FILE *fd,item_data *data,data_struct *tb)
{
	int i;
	for(i=0;tb[i].offset>=0;++i)
	{
		fprintf(fd,"%s: ",tb[i].name);
		tb[i].out(fd,((char*)data)+tb[i].offset);
		fprintf(fd,"\n");
	}
	return i;
}

int main()
{
	item_data data;
	FILE *fd=fopen("items.txt","r");
	int error=file_read_item(fd,&data,item_data_struct);
	if(error<0) printf("Error: readed only %d fields\n",-error);
	else show_item(stdout,&data,item_data_struct);
	return 0;
}

plik "items.txt"

13
Towar ekstra klasy
Do palenia, do polubienia, dla zdrowia
0.005
19.01.2021
99
666
31.12.2021
0
_13th_Dragon napisał(a):

Wszystko z tobą jasne. Zaraz będzie potrzeba wczytanie tegoż z ekranu, import/export do json itp. I wszędzie będzie taka litania case'ów?

i dyskusje były niepotrzebne

0

@AnyKtokolwiek:

AnyKtokolwiek napisał(a):

W ogóle struktura liniowa tu zachodzi? Czy "liniowa" jest tylko ,linia ze średnikiem (koniec pozycji, przejście do następnej) ?
Chyba nigdzie w wątku format pliku nie był podany z pełną ścisłością???

Racja, nie nastąpił pokaz formatu pliku i już to nadrabiam :

1;nazwa1;opis1;data1;6.8;data1;1;1;
2;nazwa2;opis2;data2;1.5;data2;2;1;
3;nazwa3;opis3;data3;3.2;data3;3;0;

@_13th_Dragon

_13th_Dragon napisał(a):

Wszystko z tobą jasne. Zaraz będzie potrzeba wczytanie tegoż z ekranu, import/export do json itp. I wszędzie będzie taka litania case'ów?

Niestety nie wpadłem na inny pomysł, nie jestem specem od programowania, przyszła mi do głowy możliwość z 'case' więc ją wykorzystałem.
No i dodatkowo nie chciałbym korzystać z gotowców tylko zależy mi na zrozumieniu tego a nie użyciu szablonu bez zrozumienia

1
#include <stdio.h>

#define TOSTR(value) #value
#define ASSTR(value) TOSTR(value)
#define STRFORMAT(length) " %" ASSTR(length) "[^;];"

#define item_name_len 32
#define item_desc_len 128
#define date_len 10
typedef struct _item_data
{
	long id;
	char name[item_name_len+1];
	char desc[item_desc_len+1];
	char period_of_origin[date_len+1];
	float weight;
	char add_date[date_len+1];
	int condition;
	int avalibility;
}item_data;

#define SCANFORMAT \
	" %d;" \
	STRFORMAT(item_name_len) \
	STRFORMAT(item_desc_len) \
	STRFORMAT(date_len) \
	" %f;" \
	STRFORMAT(date_len) \
	" %d;" \
	" %d;"

#define PRINTFORMAT \
	"id: %d\n" \
	"Name: %s\n" \
	"Description: %s\n" \
	"Origin: %s\n" \
	"Weight: %.3f\n" \
	"Added: %s\n" \
	"Condition: %d\n" \
	"Avalibility: %d\n\n"

int main()
{
/*///
    FILE *source=fopen("data.txt","r");
    item_data data;
    fscanf
/*/
    char source[]="13;trawka;do palenia;31.12.2021;6.8;19.01.2021;100;666;";
    item_data data;
    sscanf // fscanf też zadziała
//*///
	(
		source,
		SCANFORMAT,
		&data.id,
		data.name,
		data.desc,
		data.period_of_origin,
		&data.weight,
		data.add_date,
		&data.condition,
		&data.avalibility
	);
	printf
	(
		PRINTFORMAT,
		data.id,
		data.name,
		data.desc,
		data.period_of_origin,
		data.weight,
		data.add_date,
		data.condition,
		data.avalibility
	);
	return 0;
}
0

@_13th_Dragon: No teraz to już mi się wszystko pomieszało, nie rozumiem jak ten fragment kodu miałby mi pomóc, proszę o objaśnienia

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