Lite frågor om ANSI C och stränghantering samt FILE * och funktioner.

Här diskuteras programmering och utveckling
Användarvisningsbild
ZerQ
Inlägg: 160
Blev medlem: 01 aug 2007, 08:40
OS: Annat GNU/Linux
Ort: Ornsköldsvik
Kontakt:

Lite frågor om ANSI C och stränghantering samt FILE * och funktioner.

Inlägg av ZerQ »

Hejsan

Jag sitter i ANSI C och donar med ett mycket enkelt cd-register. Registret innehåller artist och skivtitel och detta sparas ner till hårddisken till en textfil. Programmet innehåller en meny och i den kan man välja på att öppna registret, skriva poster, radera poster och sortera registret.

Jag öppnar filen i main() och skickar en filpekare till varje funktion, jag har i dagsläget skrivit funktionen för öppning och skrivning till registret. Skall börja med funktionen radera poster och det är där det börjar att strula lite, jag har i textfilen grupperat artisten och titeln med en nyrad och har sedan en tomrad emellan varje post.

Hur gör jag för att kunna söka och radera en post, jag skall använda strcat() funktionen för att kunna jämföra strängarna men jag känner inte rikrigt att jag har koll på hur jag skall behandla och i vilket faktiskt format det inlästa strängen ifrån filen blir. Jag vill ju kunna radera en post som ligger placerad som exempelvis nr 3 i den totala mängden poster...? Likadant blir det när jag skall sortera upp filen så att den listar posterna efter namnet på artisten i bokstavsordning, jag greppar inte hur jag skall behandla strängen så att det blir korrekt. Har inte riktig koll på detta så frågar er om lite hjälp.

Sedan har jag lite problem med FILE och hanteringen av detta i funktioner, Jag hade tänkt öppna filen för läsning/skrivning i varje funktion men då får jag kompileringsfel som säger att deklarationen av FILE inte stämmer. Öppnar jag dock filen i main så går det bra men jag får varningar om att inte formal och actual parameter stämmer när jag skickar med filpekaren i funktionsanropet ifrån main.

Jag har klistrat in koden för hela programmet men den är ganska lång, ni får plocka ut det som jag frågar om :) Jag är er grymt tacksam om ni kan hjälpa mig i rätt riktning... ;D

Kod: Markera allt

///////////////////////////////////////////////////////////////////////
// Namn:		Johnny Lindberg
// Datum:		2005-12-26
// Version:		Ver. 1.0
// Beskrivning: Detta program fungerar som ett enkelt 
//				cd-register. Man kan skriva in och radera 
//				titlar och söka samt sortera dom.
//
///////////////////////////////////////////////////////////////////////

//Denna rad definierar vilket bibliotek som skall användas
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>

// Makro definieringar
#define TRUE 1

// Funktionsprototyper
void skrivInformation(void);
void menyVal(void);
void oppnaRegister(fpPek);
void skrivaPost(fpPek);
void raderaPost(void);
void sorteraRegister(void);

//Detta är huvudfunktionen
int main(void)
{
	//Variabel och pekardeklaration och tilldelning
	FILE *fpPek;
	int iMenyVal = 0;
		
	// Nu skriver vi ut lite informationstext om programmet
	skrivInformation();

	// Nu startar meny-slingan
	while (TRUE)
	{
		menyVal(); // Skriv ut menyn
		printf("  Ange ett menyval (1-5), avsluta med enter: ");
		scanf_s("%d", &iMenyVal, 1);
		fflush(stdin);
		
		// Nu skall vi kontrollera vad du har skrivit in
		switch(iMenyVal)
		{
		case 1: 
			if ((fpPek = fopen("cd-register.txt", "r")) == NULL)
			{
				printf("Filen kunde inte \x94ppnas\n\n");
				exit(1);
			}
			oppnaRegister(fpPek);
			break;
		
		case 2: 
			if ((fpPek = fopen("cd-register.txt", "a")) == NULL)
			{
				printf("Filen kunde inte \x94ppnas\n\n");
				exit(1);
			}
			skrivaPost(fpPek);
			break;
		
		case 3: 
			if ((fpPek = fopen("cd-register.txt", "w+")) == NULL)
			{
				printf("Filen kunde inte \x94ppnas\n\n");
				exit(1);
			}
			raderaPost(fpPek);
			break;
		
		case 4: sorteraRegister();
			break;
		
		case 5: printf("Du har angett att du vill avsluta registret\n\n");
			fclose(fpPek); // stäng filen så att den inte är öppen om jag av misstag har öppnat den
			exit(0);
			break;
		
		default: printf("Du har angett ett felaktigt menyval!\n");
			printf("Ange nytt v\x84rde!\n\n");
			break;
		}
	}


	// Lite avslutande text
	printf("\nTack f\x94r att du har anv\x84nt detta program, hejd\x86!\n\n");
	
	return(0);
}
/* Funktionerna börjar här */
/*
*
*
*/
/* Denna funktion skriver ut informationstext för att användaren skall förstå programmets 
	funktion och vad denna skall göra för att programmet skall utföra det användaren vill */
void skrivInformation(void)
{
	printf("V\x84lkommen till programmet CD-Registret:\n\n");
	printf("H\x84r kan du skriva vilka in cd-skivor du har och sedan kan s\x94ka p\x86\n");
	printf("dom eller ta bort ur registret. V\x84lj vad du vill g\x94ra ur menyn nedan.\n\n");

}
/*
*
/*
/* Denna funktion skriver ut menyn för programmet */
void menyVal(void)
{
	printf("  1  Visa cd-registret\n");
	printf("  2  Skriv in en ny titel\n");
	printf("  3  Ta bort en titel\n");
	printf("  4  Sortera CD-registret\n");
	printf("  5  Avsluta cd-registret\n");
}
/*
*
*/
/* Denna funktion öppnar registret för listning av alla posterna */
void oppnaRegister(fpPek)
{
	// Variabel och pekar deklaration och tilldelning
	char cFilData;

	// Nu läser vi in filens innehåll och skriver ut den
	printf("\nDessa poster finns i cd-registret.\n");
	while((cFilData = fgetc(fpPek)) != EOF)
	{
		putchar(cFilData);
	}

	// Skriv ut några tomrader för snygggare visning och stäng sedan filen
	printf("\n\n");
	fclose(fpPek);
	
}
/*
*
*/
/* Denna funktion ger användaren möjlighet att skriva till registret och addera poster */
void skrivaPost(fpPek)
{
	// Variabel och pekar deklaration och tilldelning
	char sArtist[201];
	char sTitel[201];
	
	char cRunState = 'j';
	int *iAntalPoster;
	iAntalPoster = malloc(sizeof(int));
	*iAntalPoster = 0;
	
	// Nu skall vi hämta in artist och titeln på skivan
	while ((cRunState == 'j') || (cRunState == 'J'))
	{
		// Nu hämtar vi in artisten och titeln ifrån användaren
		printf("\nSkriv in artist och skivtitel (max 200 tecken), avsluta med enter.\n");
		printf("Ange artist: ");
		gets_s(sArtist, 200);
		fflush(stdin);
			
		printf("Ange titel:  ");
		gets_s(sTitel, 200);
		fflush(stdin);
		
		// Nu skriver vi detta till filen
		fprintf_s(fpPek, "%s\n", sArtist);
		fprintf_s(fpPek, "%s\n\n", sTitel);
				
		// Nu frågar vi om vi vill skriva in fler poster
		printf("\n\nVill du skriv in fler titlar, j/n? ");
		scanf_s("%c", &cRunState);
		fflush(stdin);
		*iAntalPoster += 1;
	}
	printf("Du skrev in %d poster denna g\x86ng\n\n", *iAntalPoster);
	fclose(fpPek);

	/* Nu frigör vi minnet och pekar alla pekare på NULL så att dom inte 
	av misstag ändrar något som inte skall påverkas */
	free(iAntalPoster);
	iAntalPoster = NULL;
}
/* 
*
/*
/* Denna funktion ger användaren möjlighet att radera poster i registret */
void raderaPost(void)
{
	// Variabel och pekar deklaration och tilldelning
	char sRaderaArtist[201];
	char sRaderaTitel[201];
	char cRunState = 'j';
	
	
	// Nu skall vi hämta in artist och titeln på skivan
	while ((cRunState == 'j') || (cRunState == 'J'))
	{
		// Nu hämtar vi in artisten och titeln ifrån användaren
		printf("\nSkriv in artist och skivtitel (max 200 tecken), som du vill radera\n");
		printf("Avsluta varje inmatning med enter.\n");
		printf("Ange artist: ");
		gets_s(sRaderaArtist, 200);
		fflush(stdin);
			
		printf("Ange titel:  ");
		gets_s(sRaderaTitel, 200);
		fflush(stdin);

		// Sök upp och radera posten som skrivits in
		
		
		// Nu frågar vi om vi vill skriva in fler poster
		printf("\n\nVill du radera fler titlar, j/n? ");
		scanf_s("%c", &cRunState);
		fflush(stdin);
	}
}
/*
*
/*
/* Denna funktion sorterar registret efter namn eller titel, beroende på vad användaren väljer */
void sorteraRegister(void)
{
	printf("\nFunktionen sorteraRegister\n\n");
}
Säljer massa saker kolla in min hemsida http://www.befta.com
Användarvisningsbild
gasol
Inlägg: 405
Blev medlem: 27 jul 2007, 14:57
Kontakt:

SV: Lite frågor om ANSI C och stränghantering samt FILE * och funktioner.

Inlägg av gasol »

antalPoster i skriv fil, behöver inte alls vara en int pekare ut skulle lika gärna kunna vara en int.

Den enklaste lösningen på ditt problem, speciellt vid ett sånt här litet register är att inte lagra registret i en fil, utan i programmet.

spara alla poster i en array med structar

Kod: Markera allt

//pekare till strängar, lite mer minneseffektivt
struct post {
   char *sArtist;
   char *sTitel;
}

Kod: Markera allt

//arrayer för strängarna lite mindre minneseffektivt men lättare
struct post {
   char sArtist[201];
   char sTitel[201];
}
När du ska ta bort en post ur listan så kör du bara memmove(3), eller så har du en boolean i varje struct som säger om dessa är borttagna eller inte.

För att spara till fil så tar du bara bort filen och skriver din array till filen.

För att sortera dina poster så kan du använda qsort()

void qsort(void *base, size_t nmemb, size_t size,
                  int(*compar)(const void *, const void *));

qsort vill ha in en pekare till din array (base) hur många element som är i listan (nmemb)
hur stor element är sizeof(post) (size) sedan en funktions pekare till en funktion som tar in två void pekare och returnerar en int.

exemempel på en sån funktion är:

Kod: Markera allt

int comp(void *v1, void *v2) {
   struct post *p1, *p2;

   p1 = (struct post*) v1;
   p2 = (struct post*) v2;

    return strcmp(p1->sArtist, p2->sArtist);
}
The Black Mountain Scorpion Hoedown Bluegrass Experience Gang
From Left to Right: Wizard on Bicycle, Wizard on Bicycle, Wizard on Bicycle, Wizard on Bicycle, Wizard on Bicycle.
Användarvisningsbild
ZerQ
Inlägg: 160
Blev medlem: 01 aug 2007, 08:40
OS: Annat GNU/Linux
Ort: Ornsköldsvik
Kontakt:

SV: Lite frågor om ANSI C och stränghantering samt FILE * och funktioner.

Inlägg av ZerQ »

ok jag förstår delvis vad du menar, då skall jag skapa en vektor vars varje indexinnehåll kommer att vara en struktur. Men iom att jag kommer att skriva in flera poster och inte vet hur många det blir så hur gör jag då för deklareringen av vektorn, skall jag använda pekare och senare skapa plats dynamiskt eller skall jag i förväg definiera att vektorn skall kunna innehålla säg 200 poster?

Jag blev lite borttappad där nämligen, har svårt att förstå hur detta fungerar. Jag ser det som att jag alltid måste veta storleken av det jag skapar men kan man alltså utan att vet storleken skapa en vektor som kommer att rymma alla posterna jag skriver in.
Säljer massa saker kolla in min hemsida http://www.befta.com
Användarvisningsbild
gasol
Inlägg: 405
Blev medlem: 27 jul 2007, 14:57
Kontakt:

SV: Lite frågor om ANSI C och stränghantering samt FILE * och funktioner.

Inlägg av gasol »

Det finns ett gäng olika lösningar på detta problem, som ofta återkommer när du programmerar, en lösning är att i din fil med alla poster, först lagra hur många poster det finns i filen.

När programmet sedan skapar nya poster skulle du kunna ha en en annan array, som du skapar med storleken, låt oss säga 10, när den blir full så får du allokera mer minne också dylikt. Där bara nya poster läggs in, sedan när alla poster ska sorteras så måste du slå ihop dessa listor dock.

Ett annat sätt är att ha en länkad lista, detta är den snyggare lösningen, kolla upp linked list på wikipedia, det är nog för dig den mest effektiva lagringsmodellen om du bortser från sorteringen.

Exempel här är next en pekare till nästa post på så vis kan du itererar listan.

Kod: Markera allt

struct post {
   char *sArtist;
   char *sTitel;
   struct post *next;
}
Eventuellt så kan du ha en pekare till föregående element också, struct post *prev. Detta blir lättare vid borttagning.


Ett tips är att kolla upp realloc (3?), den kommer att utöka minnet du har allokerat till en viss pekare tex.

char *apa = malloc(40 * sizeof(char));

om du behöver mer plats så kan du köra

apa = realloc(apa, 80 * sizeof(char)); // OBS är inte säker på syntaxen, sitter hos en kompis på hans windoze burk :(
The Black Mountain Scorpion Hoedown Bluegrass Experience Gang
From Left to Right: Wizard on Bicycle, Wizard on Bicycle, Wizard on Bicycle, Wizard on Bicycle, Wizard on Bicycle.
Megamannen
Inlägg: 75
Blev medlem: 06 sep 2007, 19:50
Ort: Sverige

SV: Lite frågor om ANSI C och stränghantering samt FILE * och funktioner.

Inlägg av Megamannen »

Kod: Markera allt

// Funktionsprototyper
void skrivInformation(void);
void menyVal(void);
void oppnaRegister(fpPek);
void skrivaPost(fpPek);
void raderaPost(void);
void sorteraRegister(void);
I prototyperna ska du ange vilken typ av inparameterar som skickas med. Du har bara skrivit fpPek. Kompilatorn har ingen aning om vad det är för någon datatyp. Vissa antar då att det är en int. Korrekterat stycke:

Kod: Markera allt

// Funktionsprototyper
void skrivInformation(void);
void menyVal(void);
void oppnaRegister(FILE* fpPek);
void skrivaPost(FILE* fpPek);
void raderaPost(void);
void sorteraRegister(void);
Sedan ska du självklart även ändra när nere där du definerar funktionerna också. Från fpPek till FILE* fpPek.
Software can become hardware!
Användarvisningsbild
ZerQ
Inlägg: 160
Blev medlem: 01 aug 2007, 08:40
OS: Annat GNU/Linux
Ort: Ornsköldsvik
Kontakt:

SV: Lite frågor om ANSI C och stränghantering samt FILE * och funktioner.

Inlägg av ZerQ »

Javisst vad eneklt det är ibland, har suttit och tittat på koden i dagar nu och inte riktigt fattat vad som kompiulatorn bråkar om, nu är det löst iaf. tack så mycket [Megamannen]

Nu har jag laddat ner lite litteratur om listor och funderar på om detta skulle vara en snygg lösning, frågan är om den extrakoden som behövs för det är försvarbart iom att registret antagligen inte kommer att innehålla så jättemånga poster, men ideén ser mycket lovande ut och jag skall definitivt använda det i kommande program.

Jag måste dock klura ut hur jag enklast skannar arrayn så att jag får fram indexet för nästa tomma plats så jag kan använda detta för att lägga till fler poster i arrayn, med append i filhanteringen. Lösningen med att spara en separat vektor innehållande hur många poster som finns är ju inte så dumt men finns det en enklare lösning tro?

suck ibland känns det som om jag inte ens har börjat skrapa på ytan av C och dess funktioner :(
Säljer massa saker kolla in min hemsida http://www.befta.com
Skriv svar

Återgå till "Programmering och webbdesign"