17 svar
459 visningar
egghuvud 21 – Fd. Medlem
Postad: 18 jan 2018 23:17

läsa in från textfil, varje inläst rad ska sparas i en struct

Hej, jag håller på med en programmeringsuppgift men sitter fast för nuläget. Uppgiften går ut på att man har en textfil med olika varor, varav dessa varor har tio stycken element.(varunummer, namn, stil, etc.) Dessa element har datatyperna int, char[100], char[50], char[20] och float. Med denna textfil ska man sedan göra så att en inläst rad skall sparas i en struct, sedan skall man skapa ett "fält" med plats för 100 stycken av dessa varu-structer. Det är här jag sitter fast, någon som är duktig på detta?

 

Här är koden som jag har i nuläget.

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

void start(void)
{

char *oneline, *tok;
char envara[256];
char delim[] = ",";
FILE *fp;

if ((fp = fopen("varor.csv", "r")) == NULL)
{
fprintf(stderr, "Filen varor.csv gick inte att öppna\n");
exit(-1);
}
while (fgets(envara, 256, fp))
{

fgets(envara, 256, fp);
envara[strlen(envara) - 1] = '0'; 
printf("%s\n\n", envara);
oneline = strdup(envara);
tok = strtok(oneline, delim);


while (tok != NULL)
{
printf("%s\n", tok);
tok = strtok(NULL, delim);
}

}

 

free(oneline); free(tok);
fclose(fp);

}

PeBo 540
Postad: 18 jan 2018 23:38

Du har en lite märklig signatur på din huvudmetod -- den heter main() och är void, men du vill egentligen ha en int main() i ett c-program.

Du har också en while(fgets()) och som första rad i loop-blocket gör du fgets igen, så du läser bara varannan rad.

Förutom det är det nog ganska rättfram. Har du kolla på definitioner av structar och hur du allokerar minne för dom?

egghuvud 21 – Fd. Medlem
Postad: 19 jan 2018 00:42

Hej, tack för svaret! Jag är ny inom c-programmering så är inte direkt en stjärna på det, än. Jag har en int main() som är till för en meny. Vad är bäst att göra med void start(void) som jag har nu?

Hoppsan, dubbla fgets()) var ett misstag!

Jag har kollat runt lite men får inte riktigt fram en tanke för hur det ska gå till, är ju ny inom detta. Men har försökt göra en struct med de olika datatyperna men vet inte hur jag ska tilldela dem och vilka funktioner att anropa. Sedan antar jag att dessa structer ska placeras i en array med 100 platser då? Tacksam för hjälp

PeBo 540
Postad: 19 jan 2018 11:11

Du kanske kan ta inspiration av det här exemplet på hur man allokerar 100 element av en strukt med strängar som är 100 långa. Det är statiskt allokerat data (på stacken), men jag tror det räcker för att förstå biten med hur du definierar och addresserar struktar och data i dessa.

Du kan placera data i name genom att addressera elementet name i det 10:e elementet genom

items[9].name

Du behöver troligen göra något av typen strncpy() och kan då behöva använda "&"-tecknet för att konvertera till en pekare till objektet du ska kopiera till.

#include <stdio.h>

int main(){
struct {
int number;
char name[100];
char type[100];
char style[100];
float price;
} items[100] = {1, "foo", "bar", "com", 10.0};
printf("Hello, world. Item is \n"
"number: %d\n"
"name: %s\n"
"type: %s\n"
"style: %s\n"
"price: %f\n", items[0].number, items[0].name, items[0].type, items[0].style, items[0].price);
}

egghuvud 21 – Fd. Medlem
Postad: 19 jan 2018 12:53

Tackar! Ska testa detta!

egghuvud 21 – Fd. Medlem
Postad: 19 jan 2018 13:26 Redigerad: 19 jan 2018 13:39

I raden där det står  items[100]={1, "foo", "bar", "com", 10,0}; 

Hur ska den ändras för att passa min kod? Samt hur får jag raderna i textfilen att tilldelas de olika datatyperna? det vill säga att t.ex "int nummer" tilldelas serienumret som står i textfilen. alla olika element i textfilen är uppdelade med komma tecken.

 

Det här har jag i nuläget. Är jag helt ute och cyklar eller?

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

void start(void)
{

char *oneline, *tok;
char envara[256];
char delim[] = ",";
FILE *fp;


struct vara
{
int nummer;
char namn[100];
float pris;
float volym;
char typ[100];
char stil[100];
char forpackning[20];
char land[20];
char producent[50];
float alkoholhalt;

} items[100] = { 1, "foo", "bar", "com", 10.0 };
printf("Hello, world. varan är \n"
"nummer: %d\n"
"namn: %s\n"
"pris: %f\n"
"volym: %f\n"
"typ: %s\n"
"stil: %s\n"
"förpackning: %s\n"
"land: %s\n"
"producent: %s\n"
"alkoholhalt: %f\n", items[0].nummer, items[0].namn, items[0].pris, items[0].volym, items[0].typ,
items[0].stil, items[0].forpackning, items[0].land, items[0].producent, items[0].alkoholhalt);

if ((fp = fopen("varor.csv", "r")) == NULL)
{
fprintf(stderr, "Filen varor.csv gick inte att öppna\n");
exit(-1);
}
while (fgets(envara, 256, fp))
{

envara[strlen(envara) - 1] = '0'; // Ta bort radslutstecknet
printf("%s\n\n", envara);
oneline = strdup(envara);
tok = strtok(oneline, delim);


while (tok != NULL)
{
printf("%s\n", tok);
tok = strtok(NULL, delim);
}

}

 

free(oneline); free(tok);
fclose(fp);

}

PeBo 540
Postad: 19 jan 2018 13:37

Ersätt bara 

items[100]={1, "foo", "bar", "com", 10,0}; 

med

items[100];

Det jag hade till höger om = var en initierare som jag hade med för att kunna skriva ut något utan att ha läst in något från en fil.

egghuvud 21 – Fd. Medlem
Postad: 19 jan 2018 13:42

Har försökt lite med strcpy. Jag får en utskrift i CMD men förstår inte hur till exempel "int nummer" ska tilldelas de siffrorna som symboliserar serienumret i textdokumentet. 

Här är en exempel rad från textdokumentet:

82476,Watermelon Dorado Double India Pale Ale,31.90,355.00,Ale brittisk-amerikansk stil,Imperial/Dubbel IPA,Flaska,USA,Ballast Point Brewing,10.00

Ber om ursäkt för att jag är trögsinnad!

PeBo 540
Postad: 19 jan 2018 14:10 Redigerad: 19 jan 2018 14:11

Din loop

while(fgets())

skulle kunna vara en for-loop istället

for(i = 0; i < 100 && fgets(envara, 256, fp); i++){

som räknar upp ett index "i", och detta i kan vara index in i dina items

items[i].nummer

kan tilldelas det värde du läst in, men du måste använda funktioner som atof och atoi för att omvandla texten till heltal och flyttal

items[i].nummer = atoi(tok);

items[i].pris = atof(tok);

strncpy(&items[i].land, tok, strlen(tok));

och så vidare. Jag har inte kollat detaljerna där så det kan vara något trasigt, men på det viset kan du läsa in från text-filen till den struktur du har.

Hoppas du kommer framåt lite mer med det.

egghuvud 21 – Fd. Medlem
Postad: 19 jan 2018 14:51 Redigerad: 19 jan 2018 14:56

Tack för hjälpen men märker att jag borde gått på alla föreläsningar inför detta. Kommer aldrig lyckas reda ut detta. Står t.ex att i är undeclared, vad och hur ska ge i för värde. samt sista raden i koden du skickade till mig, skall jag göra en sån för alla "char" typer?

PeBo 540
Postad: 19 jan 2018 15:15

Precis, jag lämnade det där med deklarationen av i som en grej du kunde lösa själv. Efter raden

FILE *fp;

kan du lägga till

int i;

så kommer den biten att vara löst. Och ja, en sån strncpy() är för alla strängar (char * typer) -- den kopierar allt data fram till och med den avslutande noll-byten..

En sak till: När du får meddelandet "undeclared", så handlar det inte om att du inte har givit "i" ett värde, utan att du inte har förklarat vad "i" är för typ. En deklaration beskriver vilken typ saker är, att ge dem ett värde kallas för att definiera dom. Det där kan bli viktigt längre fram.

Jag håller inte med om att du inte kan reda ut det här -- du är på god väg. Fortsätt bara och säg till om du kör fast. En sak till -- den inre loopen där du gör strtok() kan vara svår att behålla som en loop -- du får nog veckla ut koden och läsa in en parameter i taget. Vi kan snygga till det sen när du har grisat dig igenom till något som precis funkar. Ett alternativ kan vara att använda sscanf(). Det blir mindre kod, men kan på sätt och vis ge fel som är svårare att debugga.

Upp med hakan -- snart framme. :)

PeterÅ 842
Postad: 20 jan 2018 14:51

Tror att du behöver lära dig grunderna inom C-programmering innan du ger dig in på mer avancerad programmering. Du skriver: "men märker att jag borde gått på alla föreläsningar".
Det stämmer säkert. Du kan inte springa innan du kan gå. Jag försöker inte misskreditera dig eller vara elak, vill bara att du förstår att man måste kunna grunderna först.

PeBo 540
Postad: 20 jan 2018 15:48

Jag förstår precis vad @PeterÅ menar (och håller med), men det finns inget som slår konkret knåpande med mjukvara för att lära sig, så var inte rädd för att fortsätta försöka. Man lär sig genom att försöka, och barn lär sig att gå genom att försöka, ramla, resa sig, försöka igen och så vidare. Jag har inte sett ett barn som lärt sig gå genom att gå på lektioner. Just C är ett extremt enkelt språk till sin struktur och det går att lära sig på en dag eller två, men att bli duktig tar många år. Att det sen kräver lite erfarenhet att förstå manual-sidor för funktioner och förstå hur man sätter ihop bra kod är en annan sak.

Oavsett hur man närmar sig uppgiften finns det många komplement till övning, men ingen ersättning.

Den klassiska boken för att lära sig C är Kernighan & Ritchie's ANSI C (https://github.com/germanoa/compiladores/blob/master/doc/ebook/The%20C%20Programming%20Language%20-%202nd%20Edition%20-%20Ritchie%20Kernighan.pdf) -- man kan sitta ner och gå igenom den, och sen kan man det nödigaste. Resten är övning.

Happy hacking!

:)

egghuvud 21 – Fd. Medlem
Postad: 21 jan 2018 19:45 Redigerad: 21 jan 2018 19:49

Får de här felmeddelandena, hur kan jag lösa detta?

expected 'char *' but argument is of type 'char (*)[100]

warning: passing argument 1 of 'strncpy' from incompatible pointer type [-Wincompatible-pointer-types]
strncpy(&items[i].namn, tok, strlen(tok));

Samt att om jag tar bort []-fälten på alla char typer, så skrivs inga felmeddelanden ut men då slutar  programmet fungera när det körs. 

 

 

int i;
struct vara
{
int nummer;
char namn[100];
float pris;
float volym;
char typ[100];
char stil[100];
char forpackning[20];
char land[20];
char producent[50];
float alkoholhalt;

} items[100];

items[i].nummer = atoi(tok);
items[i].pris = atof(tok);
items[i].volym = atof(tok);
items[i].alkoholhalt = atof(tok);
strncpy(&items[i].namn, tok, strlen(tok));
strncpy(&items[i].typ, tok, strlen(tok));
strncpy(&items[i].stil, tok, strlen(tok));
strncpy(&items[i].forpackning, tok, strlen(tok));
strncpy(&items[i].land, tok, strlen(tok));
strncpy(&items[i].producent, tok, strlen(tok));

PeBo 540
Postad: 22 jan 2018 09:40

Jag tror jag lurade dig där, du ska nog dumpa &, sorry...

PeterÅ 842
Postad: 22 jan 2018 16:29

items[i].namn är redan adressen till värdet, & ska inte användas mot en array, dvs items[] ...
Men som sagt, du behöver läsa in grunderna.

egghuvud 21 – Fd. Medlem
Postad: 22 jan 2018 23:25

ni är hjältar kamrater. Ska bara mosa igenom den här kursen, har aldrig varit bra på programmering

PeterÅ 842
Postad: 23 jan 2018 16:55

egghuvud, med all respekt: Att "mosa" sig igenom en kurs. Hur tänker du nu? Har du inte valt din inriktning? Jag undrar vad du är intresserad av. Vill du svara på det?

Svara Avbryt
Close