Vinnaren i pepparkakshustävlingen!
2017-11-29, 15:36
  #1
Medlem
smellyproofs avatar
Jag har ett program som frågar användaren efter information om fordon och dess ägare. Det finns plats för 10 "fordons" poster enligt följande kod:
Kod:
typedef struct fordon { 
    char namn[15];    
    char marke[20];    
    char fordonstyp[15];
    char registeringsnummer[10];
} fordon;
  fordon f[10];
I programmet kan användaren själv mata in poster. Jag vill dock göra det möjligt för programmet att kolla om det finns en .txt fil med poster som den kan importera till "typedef struct fordon".
Jag har börjat lite på en kod genom att kolla på andra exempel men den funkar inte riktigt i nuläget:
Kod:
/*FILE *file = fopen("labb4.txt", "w");
fclose(file);
 if (file == NULL){
}
else
    {
        while (!feof(file))
        {
            //fscanf(file, "%d%s%lf", &f.namn, &f.marke, &f.fordonstyp, &f.registeringsnummer);
            fread(&f, sizeof(f),1, file);
        }
} 	
fclose(file); 

Någon som vet hur man kan lösa problemet? Poster hela den körbara koden här under spoiler:
__________________
Senast redigerad av smellyproof 2017-11-29 kl. 15:39.
Citera
2017-11-29, 17:23
  #2
Medlem
Kod:
"%d%s%lf"

Med inga mellanslag mellan de specifiers som ligger i strängen så förväntar programmet nåt såhär:

Kod:
5test0.5000

Om du inte vill att programmet ska ta emot en fil av det här formaten så kan du lägga till ett par mellanslag mellan dina specifiers:

Kod:
"%d %s %lf"

Dessutom skickar du 4 variabelpekare till scanf, men bara 3 specifiers. Antalet pekarparametrar (variabler som ska ta emot värden) ska vara lika med antalet specifiers, annars blir det problem, för att det antingen finns en variabel som programmet inte vet vad det ska göra med eller det kommer försöka läsa in ett värde och sen ha ingenstans att ställa in det i.

Och ändå försöker du ställa in en integer i en sträng-variabel, och en double (%lf) i en sträng-variabel, vilket inte kommer att gå. Om det är en integer i filen så kan man köra integer som variabeltyp också.
__________________
Senast redigerad av kanes272 2017-11-29 kl. 17:26.
Citera
2017-11-29, 22:15
  #3
Medlem
smellyproofs avatar
Citat:
Ursprungligen postat av kanes272


Och ändå försöker du ställa in en integer i en sträng-variabel, och en double (%lf) i en sträng-variabel, vilket inte kommer att gå. Om det är en integer i filen så kan man köra integer som variabeltyp också.
Tack för din hjälp. Filhanteringen är jag osäker på så har bara kollat på en annan kod, skrivit om den lite och slängt in den i min. Ska skriva om anpassa den mera nu för det verkar enligt dig som jag är på rätt väg ändå.
Citera
2017-11-29, 22:51
  #4
Medlem
smellyproofs avatar
Jag är totalt nybörjare så lita inte på min kod. All hjälp uppskattas. Okej det här är min "skriv in från fil" funktion".

När jag hade while (!feof(file)) så stannade programmet i en loop. När jag ändrade till while (feof(file)). Så fick jag istället det här konstiga felmeddelandet: bild
Citera
2017-11-30, 04:29
  #5
Avstängd
Citat:
Ursprungligen postat av smellyproof
Kod:
FILE *file = fopen("labb4.txt", "w");

Öppna filer med "r" när du ska läsa från dem. Nu blir den tom varje gång du kör programmet.

Citat:
Ursprungligen postat av smellyproof
Kod:
fclose(file);

Sen stänger du filen direkt efter, innan du har använt den?

Citat:
Ursprungligen postat av smellyproof
Kod:
while (feof(file))
{
    fscanf(...);
}

EOF-flaggan sätts inte förrän ett anrop har försökt att läsa förbi slutet av filen. Kolla den efter varje läsning, inte tvärtom. Vilket du iofs gör då du har läsanropet sist i loopen, men om/när du lägger till mer kod efter det, som använder det (eventuellt icke) lästa datat, blir det garanterat knas. Du har redan mer kod efter skulle man kunna säga: scanf()s interna som sätter variablerna.

Och beroende på slutet av formatsträngen kan EOF sättas av scanf() efter det sista lyckade anropet ("...%d"), eller det första misslyckade när det inte fanns någon data kvar alls ("...%c"). Det är scanf()s returvärde du ska kolla, och använda feof() och ferror() som komplement om du behöver mer information om vad som hände.

Citat:
Ursprungligen postat av smellyproof
Kod:
fread(&f, sizeof(f),1, file);

fread() läser data "rått" utan någon omvandling (om man även kommit ihåg att öppna filen med "b" för att stänga av radbrytningsomvandlig), tolkning eller uppdelning av den. Bytarna i filen motsvarar direkt bytarna i minnet. scanf() kan göra tre saker samtidigt åt dig (fyra om man utelämnar "b"): läsa, tolka data som formatterat och dela upp det i olika medlemmar/variabler.
__________________
Senast redigerad av B-programmerare 2017-11-30 kl. 04:34.
Citera
2017-11-30, 08:38
  #6
Medlem
kaks avatar
Använd aldrig fscanf.
Läs in hela rader med fgets och använd sscanf på den raden istället.
Citera
2017-11-30, 13:11
  #7
Medlem
smellyproofs avatar
Citat:
Ursprungligen postat av B-programmerare
text
Tack mycket bra hjälp.

Nu har jag fått funktionen att läsa in från .txt fil i alla fall. Men hur gör man ska man ändra koden, fread(&f, sizeof[](f),1, file);, så att den sparar i nästa post efter varje ny rad i .txt filen?
fread(&f[1]) och fread(&f[2] ändrar post så där kan man nog använda någon for-loop. Men vilken kod känner av nya rader i .txt filen?

För om det just nu står följande i txt filen:
test test
test test

så kommer det sparas i f[0]. Oavsett att de står på olika rader.

Skriv in från fil funktion:
Citera
2017-11-30, 13:59
  #8
Medlem
smellyproofs avatar
Jag verkar ha fått det att fungera. Fast den verkar inte fatta när rader är tomma. Nåja får lämna in det som det är om ingen annan har någon idé.
Kod:
/* Skriv in från fil */
FILE *file = fopen("labb4.txt", "r");
 if (file == NULL){
}
else
    {
        while (!feof(file)){
        for (i = 0; i < 10; i++){
          fscanf(file, "%s  %s %s %s", f[i].namn, f[i].marke, f[i].fordonstyp , f[i]. registeringsnummer); }
fread(&f, sizeof(f),1, file);}
 
}
fclose(file); 
Citera
2017-12-01, 13:01
  #9
Medlem
Citat:
Ursprungligen postat av smellyproof
Jag verkar ha fått det att fungera. Fast den verkar inte fatta när rader är tomma. Nåja får lämna in det som det är om ingen annan har någon idé.
Kod:
/* Skriv in från fil */
FILE *file = fopen("labb4.txt", "r");
 if (file == NULL){
}
else
    {
        while (!feof(file)){
        for (i = 0; i < 10; i++){
          fscanf(file, "%s  %s %s %s", f[i].namn, f[i].marke, f[i].fordonstyp , f[i]. registeringsnummer); }
fread(&f, sizeof(f),1, file);}
 
}
fclose(file); 

Citat:
Return Value
On success, the function returns the number of items of the argument list successfully filled. This count can match the expected number of items or be less (even zero) due to a matching failure, a reading error, or the reach of the end-of-file.

Om raden är tom, så ska returnvärdet vara noll. Kolla returnvärdet och om det inte är noll, fortsätt inte med att sätta in värdena i ett objekt i arrayen. man måste ändra på loopen lite för att få det att funka.
Citera

Stöd Flashback

Flashback finansieras genom donationer från våra medlemmar och besökare. Det är med hjälp av dig vi kan fortsätta erbjuda en fri samhällsdebatt. Tack för ditt stöd!

Stöd Flashback