Hallo Freunde.
Ich habe eine kleines Zeigerproblem:
In Nachfolgendem Beispielquelltext bekomme ich immer einen SIGSEV bei Ausführung und ich bekomme schon bei der Kompilierung Fehler weil angeblich ein falscher Typ zurückgegeben wird.
Wenn ich eine explizite Typkonvertierung mache bekomme ich Warnungen und bei Ausführung den beschriebenen SIGSEV (Segmentation Fault).
Ich habe von Zeigern leider noch nicht so die Kenne, da ich mihc mit C bisher seltener befasst habe. Bitte helft mir, da ich diese Sachen für die Arbeit lernen muss.
Ich wäre auch für jeden Hinweis auf andere grobe Patzer dankbar.
Apropos: Ich habe noch keine Funktionen eingebaut, welche den Speicher aufräumen, da bin ich bisher noch nicht zu gekommen, allerdings ist es nicht schlimm, da ich ohnehin nur mit einer verketteten Liste arbeite(n möchte)
Erstmal vielen Dank für jede Hilfe…
… und hier der Quelltext:
/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\* Copyright (C) 2004 by Alexander Fischer \*
\* [email protected] \*
\* \*
\* This program is free software; you can redistribute it and/or modify \*
\* it under the terms of the GNU General Public License as published by \*
\* the Free Software Foundation; either version 2 of the License, or \*
\* (at your option) any later version. \*
\* \*
\* This program is distributed in the hope that it will be useful, \*
\* but WITHOUT ANY WARRANTY; without even the implied warranty of \*
\* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the \*
\* GNU General Public License for more details. \*
\* \*
\* You should have received a copy of the GNU General Public License \*
\* along with this program; if not, write to the \*
\* Free Software Foundation, Inc., \*
\* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. \*
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/
#include
#include
#include
#include
#include
/\*
ToDo Liste:
--\> Speicherfreigabe noch in cleanup() einbauen (Speicher der verketteten Liste)
--\> Datensatzedit fertmachen:
\-\> Datensätze richtig anzeigen lassen
\-\> Die Fenster ausgabe in edit\_record ist erstmal wichtig
\-\> edit\_specified\_record() noch bauen
\-\> Datensatz löschen noch einbauen
--\> Übersicht einbauen
\-\> Kilometer/ Verbrauch insgesamt etc.
\*/
struct record
{
int datum;
float getankt;
float kosten;
float tachostand;
struct record \*next; //Pointer auf nächstes Struct wegen verketteter Liste
};
void malloc\_fail( void );
void fail( int error, int line);
/\*
Mögliche Fehlercodes:
1= Datei E/A
2= Memory Allocation Error (Nicht für Fenster, dort dann malloc\_fail())
\*/
void cleanup ( void ); //Aufräumarbeiten zum Programmende
void splash\_screen( void );
void addtolist( struct record \*newr );
int load\_data( void );
int save\_data( void );
int menu( void );
int overview( void );
int new\_record( void );
int edit\_record( void );
int is\_numeric( char input );
int edit\_specified\_record( struct record \*editr );
struct record \*firstrecord;
struct record \*header;
//List Header
WINDOW \*p\_Win;
int main(int argc, char \*argv[])
{
int value\_menu = 1;
initscr();
/\* Ein Curses Window öffnen; bei Fehler die Funktion malloc\_fail aufrufen und das Programm killen \*/
if((p\_Win = newwin(LINES,COLS,0,0)) == ((WINDOW \*) NULL)) malloc\_fail();
/\* Mein Splash Screen \*/
splash\_screen();
/\*So, hier wirds interessant: Gespeicherte daten schon mal spontan in den Arbeitsspeicher laden, werden
keine Daten gelesen, dann gibt load\_data eine 1 (TRUE) raus und der Header wird auf NULL gesetzt\*/
if(load\_data())
{
firstrecord = NULL;
header = NULL;
}
//Die Schleife für das Menü
while(value\_menu)
{
value\_menu = menu();
}
//Programmende...
cleanup(); //Programmcurses beenden
printf( "Das Programm wurde normal beendet!\n" );
return 0;
}
void malloc\_fail( void )
{
/\* Programm KILL Funktionen, wenn bei curses etwas schief geht!\*/
clear();
mvcur(0, 4, 0, 0);
refresh();
endwin();
printf( "Achtung! Nicht genügend Arbeitsspeicher, oder Fehler bei der Zuweisung von Arbeitsspeicher.\n\nDas Programm wird unnormal beendet! Eventuell sind Ihnen Daten verloren gegangen." );
}
void fail( int error, int line )
{
cleanup(); //Curses beenden
switch(error)
{
case 1:
printf( "Datei E/A Fehler!" );
exit(error);
break;
case 2:
printf( "Es konnte kein Speicher reserviert werden. Fehler beim reservieren des Arbeitsspeichers." );
exit(error);
break;
default:
printf( "Unbekannter Fehler!: %d", error );
exit(error);
break;
}
}
void cleanup( void )
{
/\*hier rufen wir die Funktionen auf um curses zu beenden nachdem das Bild ggeklärt und der
Cursor zurückgestzt worden ist\*/
clear();
mvcur(0,0,0,0);
refresh();
endwin();
save\_data(); // daten speichern
}
void splash\_screen( void )
{
WINDOW \*p\_Subwin;
p\_Subwin = NULL;
if((p\_Subwin = subwin(p\_Win, 9, 23, (int)LINES/2-9, (int)COLS/3-11)) == (WINDOW \*) NULL) malloc\_fail();
box(p\_Subwin, '|', '-');
wmove(p\_Subwin, 3, 1);
waddstr(p\_Subwin, " Spritrechner");
wmove(p\_Subwin, 5, 1);
waddstr(p\_Subwin, "(c)2004 A. Fischer" );
wrefresh(p\_Subwin);
sleep(1);
delwin(p\_Subwin);
refresh();
}
int menu()
{
WINDOW \*p\_Menuwin;
p\_Menuwin = NULL;
int line = 2;
int col = 2;
char sel;
if((p\_Menuwin = newwin(8, 40, 5, 5)) == ((WINDOW \*) NULL)) malloc\_fail();
box(p\_Menuwin, '|', '-');
wmove(p\_Menuwin, line, col);
waddstr(p\_Menuwin, "1. Uebersicht");
line++;
wmove(p\_Menuwin, line, col);
waddstr(p\_Menuwin, "2. Neuen Datensatz");
line++;
wmove(p\_Menuwin, line, col);
waddstr(p\_Menuwin, "3. Datensatz bearbeiten (N/A)");
line++;
wmove(p\_Menuwin, line, col);
waddstr(p\_Menuwin, "q Programm beenden");
wrefresh(p\_Menuwin);
noecho(); crmode();
sel = getch();
switch(sel)
{
case 'q':
delwin(p\_Menuwin);
refresh();
return 0;
break;
case '1':
delwin(p\_Menuwin);
refresh();
overview();
return 1;
break;
case '2':
delwin(p\_Menuwin);
clear();
refresh();
new\_record();
return 1;
break;
case '3':
delwin(p\_Menuwin);
refresh();
edit\_record();
return 1;
break;
default:
delwin(p\_Menuwin);
refresh();
return 1;
}
echo(); nocrmode();
return 0;
}
int overview()
{
return 0;
}
int new\_record()
{
struct record \*new; new = NULL;
WINDOW \*p\_First;
char input;
input = 0;
new = (struct record \*)malloc(sizeof(struct record));
if(!(new)) fail(2, \_\_LINE\_\_);
new-\>next = NULL;
p\_First = newwin(10, 50, 5, 10);
box(p\_First, ':', (char)163);
int line = 2; int col = 2;
mvwaddstr(p\_First, line, col, "Getankte Liter:");
mvwaddstr(p\_First, line+2, col, "Preis:");
mvwaddstr(p\_First, line+4, col, "Tachostand:");
mvwaddstr(p\_First, line+6, col, "Datum(JJJJ-MM-TT):");
mvwaddstr(p\_First, line, col+20, "\_\_\_\_\_\_\_\_\_\_");
mvwaddstr(p\_First, line+2, col+20, "\_\_\_\_\_\_\_\_\_\_");
mvwaddstr(p\_First, line+4, col+20, "\_\_\_\_\_\_\_\_\_\_");
mvwaddstr(p\_First, line+6, col+20, "\_\_\_\_-\_\_-\_\_");
wrefresh(p\_First);
//Erstes Feld füllen
wmove(p\_First, line, col+20);
wrefresh(p\_First);
char eingabe[11];
int i = 0;
while((input = getch()) != 10)
{
if(i == 10) break;
input = is\_numeric(input);
if(input)
{
eingabe[i] = input;
waddch(p\_First, input);
wrefresh(p\_First);
i++;
}
}
eingabe[i] = '\0';
new-\>getankt = \*eingabe;
i=0;
//Nächstes Feld füllen
wmove(p\_First, line+2, col+20);
wrefresh(p\_First);
fflush(stdin);
while((input = getch()) != 10)
{
if(i == 10) break;
input = is\_numeric(input);
if(input)
{
eingabe[i] = input;
waddch(p\_First, input);
wrefresh(p\_First);
i++;
}
}
eingabe[i] = '\0';
new-\>kosten = \*eingabe;
i = 0;
//Nächstes Feld füllen
wmove(p\_First, line+4, col+20);
wrefresh(p\_First);
fflush(stdin);
while((input = getch()) != 10)
{
if(i == 10) break;
input = is\_numeric(input);
if(input)
{
eingabe[i] = input;
waddch(p\_First, input);
wrefresh(p\_First);
i++;
}
}
eingabe[i] = '\0';
new-\>tachostand = \*eingabe;
i = 0;
//Nächstes Feld füllen
wmove(p\_First, line+6, col+20);
wrefresh(p\_First);
fflush(stdin);
while((input = getch()) != 10)
{
if(i == 8) break;
input = is\_numeric(input);
if(input)
{
eingabe[i] = input;
waddch(p\_First, input);
if(i == 3) waddch(p\_First, '-'); //Trennstriche für das Datum verwenden
if(i == 5) waddch(p\_First, '-');
wrefresh(p\_First);
i++;
}
}
eingabe[i] = '\0';
new-\>datum = \*eingabe;
i = 0;
addtolist(new); //Funktion um die Struktur, die gerade initialisiert wurde, an die verkettete Liste anzuhängen
clear();
delwin(p\_First);
refresh();
return 0;
}
int edit\_record()
{
struct record \*temp; temp = header;
WINDOW \*p\_First; p\_First = NULL;
char input; input = (char)0;
char output[11];
int line = 2; int col = 2;
p\_First = newwin(10, 50, 5, 10);
if(!(p\_First)) malloc\_fail();
box(p\_First, '+', '+');
while((input = getch()) != 'q')
{
if(!(temp)) break;
if(input == 'e') edit\_specified\_record( temp );
temp = temp-\>next;
int line = 2; int col = 2;
mvwaddstr(p\_First, line, col, "Getankte Liter:");
mvwaddstr(p\_First, line+2, col, "Preis:");
mvwaddstr(p\_First, line+4, col, "Tachostand:");
mvwaddstr(p\_First, line+6, col, "Datum(JJJJ-MM-TT):");
//So Hier ist der Knackpunkt. Die in der Verketteten Liste gespeicherten Daten möchte ich hier ausgeben und ggfl
//editieren können. Allerdings bekomme ich immer Pointer fehler. Gezielte Typkonvertierungen führen zu einem
// Speicherzugriffsfehler.
mvwaddstr(p\_First, line, col+20, temp-\>getankt);
mvwaddstr(p\_First, line+2, col+20, temp-\>kosten);
mvwaddstr(p\_First, line+4, col+20, temp-\>tachostand);
datum = temp-\>datum;
wmove(p\_First, line+6, col+20);
int b;
for(b = 0; bnext) //Wenn der Zeiger auf das nächste Element ungleich NULL gespeichert wurde, dann muss noch ein weiteres Element existieren. Der Zeiger muss unbedingt aktualisiert werden, da er sonst auf die falsche Speicherstelle zeigt.
{
do
{
temp = (struct record \*)malloc(sizeof(struct record));
if(!(temp)) fail(2, \_\_LINE\_\_);
if(!(fread(temp, sizeof(struct record), 1, myfile))) fail(2, \_\_LINE\_\_);
actual-\>next = temp; // UNd hier wird der Zeiger aktualisiert. Den Allerletzten Zeiger muss icj nicht aktualisieren da ohnehin NULL
actual = temp;
}
while(temp-\>next);
}
return 0;
}
int is\_numeric( char input )
//Prüft, ob eingabe numerisch (float)
{
switch(input)
{
case ',':
input = '.';
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '.':
return input;
break;
default:
return 0;
}
}
void addtolist( struct record \*newr )
{
struct record \*temp; temp = NULL;
if(header == NULL)
{
header = newr;
header-\>next = NULL;
}
else
{
temp = header;
while(temp-\>next != NULL)
{
temp = temp-\>next;
}
temp-\>next = newr;
newr-\>next = NULL;
}
}
int save\_data( void )
{
struct record \*temp; temp = NULL;
FILE \*myfile; myfile = NULL;
myfile = fopen("./data", "wb");
temp = header;
if(temp)
{
do
{
fwrite(temp, sizeof(struct record), 1, myfile);
temp = temp-\>next;
} while(temp);
}
fclose(myfile);
return 0;
}
int edit\_specified\_record( struct record \*editr )
//Noch nicht fertig, soll halt einen bestimmten Datensatz ändern
{
WINDOW \*p\_First;
char input;
input = 0;
new = (struct record \*)malloc(sizeof(struct record));
if(!(new)) fail(2, \_\_LINE\_\_);
new-\>next = NULL;
p\_First = newwin(10, 50, 5, 10);
box(p\_First, ':', (char)163);
int line = 2; int col = 2;
mvwaddstr(p\_First, line, col, "Getankte Liter:");
mvwaddstr(p\_First, line+2, col, "Preis:");
mvwaddstr(p\_First, line+4, col, "Tachostand:");
mvwaddstr(p\_First, line+6, col, "Datum(JJJJ-MM-TT):");
mvwaddstr(p\_First, line, col+20, "\_\_\_\_\_\_\_\_\_\_");
mvwaddstr(p\_First, line+2, col+20, "\_\_\_\_\_\_\_\_\_\_");
mvwaddstr(p\_First, line+4, col+20, "\_\_\_\_\_\_\_\_\_\_");
mvwaddstr(p\_First, line+6, col+20, "\_\_\_\_-\_\_-\_\_");
wrefresh(p\_First);
//Erstes Feld füllen
wmove(p\_First, line, col+20);
wrefresh(p\_First);
char eingabe[11];
int i = 0;
while((input = getch()) != 10)
{
if(i == 10) break;
input = is\_numeric(input);
if(input)
{
eingabe[i] = input;
waddch(p\_First, input);
wrefresh(p\_First);
i++;
}
}
eingabe[i] = '\0';
editr-\>getankt = \*eingabe;
i=0;
//Nächstes Feld füllen
wmove(p\_First, line+2, col+20);
wrefresh(p\_First);
fflush(stdin);
while((input = getch()) != 10)
{
if(i == 10) break;
input = is\_numeric(input);
if(input)
{
eingabe[i] = input;
waddch(p\_First, input);
wrefresh(p\_First);
i++;
}
}
eingabe[i] = '\0';
editr\>kosten = \*eingabe;
i = 0;
//Nächstes Feld füllen
wmove(p\_First, line+4, col+20);
wrefresh(p\_First);
fflush(stdin);
while((input = getch()) != 10)
{
if(i == 10) break;
input = is\_numeric(input);
if(input)
{
eingabe[i] = input;
waddch(p\_First, input);
wrefresh(p\_First);
i++;
}
}
eingabe[i] = '\0';
editr\>tachostand = \*eingabe;
i = 0;
//Nächstes Feld füllen
wmove(p\_First, line+6, col+20);
wrefresh(p\_First);
fflush(stdin);
while((input = getch()) != 10)
{
if(i == 8) break;
input = is\_numeric(input);
if(input)
{
eingabe[i] = input;
waddch(p\_First, input);
if(i == 3) waddch(p\_First, '-'); //Trennstriche für das Datum verwenden
if(i == 5) waddch(p\_First, '-');
wrefresh(p\_First);
i++;
}
}
eingabe[i] = '\0';
editr-\>datum = \*eingabe;
i = 0;
return 0;
}