ubuntuusers.de

Problem in C - Segmentation Fault (Core Dumped)

Status: Gelöst | Ubuntu-Version: Nicht spezifiziert
Antworten |

scosu

Anmeldungsdatum:
28. Juni 2008

Beiträge: Zähle...

ooohhh ja klar, an sowas hatte ich garnicht gedacht. vielen dank für deine schnelle hilfe ☺

ne, sprintf reicht, weil in dem speicherbereich nur eine mysql-id abgelegt werden soll und das damit sowieso begrenzt ist...

Hello_World

Anmeldungsdatum:
13. Juni 2006

Beiträge: 3620

Ich sehe gerade, dass da ein Fehler in meinem Code war. Statt char yeahaaa = "yeahaaaaaaaa"; muss es natürlich char yeahaaa[] = "yeahaaaaaaaa";

scosu

Anmeldungsdatum:
28. Juni 2008

Beiträge: 5

hm, also das testprogramm funktioniert jetzt soweit, ich benutze übrigens strcpy, damit der zeiger nicht auf den konstanten string gesetzt wird. Das ganze habe ich jetzt auf das richtige programm übersetzt, aber da funktioniert es nichtmehr, und ich sehe einfach keinen grund, wieso es nicht funktioniert. Hier einmal die wie ich denke relevanten codestellen:

char **mysql_players;
short int *player_team;
char **player_names;
//[....]

inline int init(char *config_file)
{
//[......]
	game_id = malloc(100);
	input_line_time = 0;
	input_line = malloc(2000);
	players_invalid = 0;
	player_join_time = malloc(sizeof(unsigned long int) * max_players);
	map_id = malloc(100);
	map_start = 0;
	game_mode = DM;
	player_clan = malloc(sizeof(unsigned long int) * max_players);
	player_modifier = malloc(sizeof(float) * max_players);
	player_names = malloc(sizeof(char*) * max_players);
	player_pickup_id = malloc(sizeof(char*) * max_players);
	player_team = malloc(sizeof(short int) * max_players);
	player_voted = malloc(sizeof(short int) * max_players);
	players = 0;
	player_pickups = malloc(sizeof(int*) * max_players);
	mysql_players = (char**)malloc(sizeof(char *) * max_players);
	int i = 0;
	for(; i < max_players; i++)
	{
		player_clan[i] = 0;
		player_modifier[i] = 0;
		player_names[i] = malloc(200);
		player_pickup_id[i] = malloc(100);
		player_team[i] = UNDEFINED_TEAM;
		player_voted[i] = 0;
		mysql_players[i] = (char*)malloc(500);
		
		printf("before\n");
		strcpy(mysql_players[i], "0");
		printf("success\n");
		int n=0;
		for(; n < 9; n++)
			player_pickups[i][n] = 0;
	}
	strcpy(player_names[0], "blubba");
	printf("player_names\n");
	strcpy(mysql_players[0], "bu");
	printf("mysql_players\n");
	return 0;
}
int main(int argc, char **argv)
{
	printf("blubba\n");
	if(argc == 1)
	{
		printf("ERROR: please start this program like this: %s teeworlds-server-config.cfg", argv[0]);
		exit(2);
	}
	printf("-1\n");
	init(argv[1]);
	printf("init ready");
//[.......]
} 


und die ausgabe:

blubba
-1
1
before
success
before
success
before
success
before
success
before
success
before
success
before
success
before
success
before
success
before
success
player_names
[1]    5412 segmentation fault (core dumped)


vielen dank schonmal für hilfe ☺

Hello_World

Anmeldungsdatum:
13. Juni 2006

Beiträge: 3620

Du initialisierst mysql_players nirgends und versuchst dann, mit strcpy etwas nach mysql_players[0] zu schreiben - klar, dass das nicht funktioniert.

Übrigens würde ich Dir dringend empfehlen, die ganzen Informationen über Spieler in ein struct zu packen. Sowas hier ist nämlich einfach grauenhaft:

   player_clan = malloc(sizeof(unsigned long int) * max_players);
   player_modifier = malloc(sizeof(float) * max_players);
   player_names = malloc(sizeof(char*) * max_players);
   player_pickup_id = malloc(sizeof(char*) * max_players);
   player_team = malloc(sizeof(short int) * max_players);
   player_voted = malloc(sizeof(short int) * max_players); 


Das sollte eher so aussehen:

calloc(max_players, sizeof(struct player));

Übrigens sind statements der Form malloc(foo*bar) generell gefährlich, da immer Integer Overflows auftreten können, die dann zu einem eventuell sicherheitskritischen Buffer Overflow führen können. Offen gestanden halte ich es für völlig verfehlt, dass Du ausgerechnet C für Dein Projekt verwenden willst. Nutze Python oder Java oder C# oder so etwas, aber doch nicht so ein Rudiment aus den 70ern wie C.

scosu

Anmeldungsdatum:
28. Juni 2008

Beiträge: 5

hm, jo, das mit dem struct mache ich wohl mal, danke

aber ich deklariere und initialisiere mysql_players doch, oder muss ich da noch was anderes beachten?:

mysql_players = (char**)malloc(sizeof(char *) * max_players);
mysql_players[i] = (char*)malloc(500);
printf("before\n");
strcpy(mysql_players[i], "0");


und da funktioniert es ja mit strcpy auch nur danach iwie nichtmehr. und player_names ist ja auch praktisch das selbe, aber das funktioniert.

jo, das projekt ist in der jetzigen version in java, aber da es mit einem server laufen soll, ist es unpraktisch, dass das java-programm mindestens 15mb ram braucht. meist sind sogar von dem programm 40mb belegt. und wieso C#, funktioniert das nicht nur unter windows? ich finde c schön, außer dass ich noch nicht viel weiß.

Hello_World

Anmeldungsdatum:
13. Juni 2006

Beiträge: 3620

Oh, die Initialisierung von mysql_players hatte ich übersehen, Entschuldigung. So auf die Schnelle kann ich kein Problem erkennen, wahrscheinlich fehlt die relevante Stelle im Quellcode. Bitte stell ein Programm zusammen, das

  1. sich kompilieren lässt,

  2. den Fehler zeigt und

  3. so klein wie möglich ist.

Dann kann man Dir helfen.

lilith2k3

Avatar von lilith2k3

Anmeldungsdatum:
14. Dezember 2006

Beiträge: 2999

Wohnort: OS

Mal abgesehen davon, ob nun C die richtige Sprachwahl ist oder nicht:

Du schreibst schon einen etwas gewöhnungsbedürftigen Code.
Beherzige doch bitte den Tip von Hello World.
Es gibt in C auch so nette Dinge, wie einen Pfeiloperator 😉 "→".

Beispielsweise:

struct Playerinfo{
 char *cPlayerName;
 [...]
};

[...]

struct Playerinfo *Player;
Player=(struct *Playerinfo) malloc(sizeof *Player);

[...]

Player->cPlayerName=(char *) malloc(sizeof MAXLENGTH);

[...]
strcpy(Player->cPlayerName, "L33t");

Und zur Not gibt's noch typedefs, dann kannst Du Konstrukte wie "(struct *Playerinfo)" vereinfachen zu bspw. "(PLAYER *)".

int i = 0;
for(; i < max_players; i++)

Warum nicht gleich

for(i=0; i < max_players; i++) 

Geht sowas überein?

mysql_players = (char**)malloc(sizeof(char *) * max_players);
[...] 
mysql_players[i] = (char*)malloc(500);
[...]
strcpy(mysql_players[0], "bu");

Wenn Du (char *) reservierst, kannst Du nachher nicht nochmal das Element mit (char *) belegen.
Richtiger wäre

mysql_players[i]=malloc (500)

Das

player_names = malloc(sizeof(char*) * max_players);

sollte wohl auch eher

player_names =(char **) malloc(sizeof(char*) * max_players);


heißen.

Du willst ja ein Feld für die Namen dynamisch reservieren der Art

player_names[0]="L33t";
player_names[1]="c00LK!ll4";
[...]

P.S.: Sicherer wäre es, alle Längenangaben und Reservierungen überprüfen zu lassen 😉

Hello_World

Anmeldungsdatum:
13. Juni 2006

Beiträge: 3620

lilith2k3, Dein C-Code ist auch nicht besser. malloc liefert einen void* zurück, daher ist es unnötig und sogar schädlich, den Rückgabewert von malloc zu casten.
http://www.cpax.org.uk/prg/writings/casting.php

Das hier ist überhaupt kein gültiger Typ in C:
(struct *Playerinfo)
Ein Pointer auf struct Playerinfo heißt einfach struct Playerinfo*.

Was soll das hier:
malloc(sizeof MAXLENGTH)
Was hat das sizeof darin verloren? Und wenn die maximale Länge sowieso von vornherein feststeht, wieso dann nicht einfach

struct Playerinfo {
    char Name[MAXLENGTH];
};

?

for(i=0; i < max_players; i++)


Wo ist denn da die Deklaration von i?
In C99 kann man for(int i=0; i < max_players; i++) schreiben, dann muss man aber mit -std=gnu99 oder -std=c99 kompilieren. Das empfiehlt sich aber sowieso, da C99 einige Verbesserungen gebracht hat (z. B. Arrays variabler Länge und compound Literals).

Geht sowas überein?
Code:

mysql_players = (char**)malloc(sizeof(char *) * max_players);
[...]
mysql_players = (char*)malloc(500);
[...]
strcpy(mysql_players[0], "bu"); Wenn Du (char *) reservierst, kannst Du nachher nicht nochmal das Element mit (char *) belegen.
Richtiger wäre
Code:
mysql_players
=malloc (500) Das
Zitat: player_names = malloc(sizeof(char*) * max_players); sollte wohl auch eher
Code: player_names =(char **) malloc(sizeof(char*) * max_players); heißen.[/quote]
Das ist von vorn bis hinten großer Unfug. Wie gesagt, man sollte den Rückgabewert von malloc gar nicht casten.'

lilith2k3

Avatar von lilith2k3

Anmeldungsdatum:
14. Dezember 2006

Beiträge: 2999

Wohnort: OS

Okay, die Fehler sind dumm!

Aber

Das ist von vorn bis hinten großer Unfug. Wie gesagt, man sollte den Rückgabewert von malloc gar nicht casten.

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

int main(void)
{
 char **mysqlplayers;
 int i;
 mysqlplayers=(char **) malloc (sizeof (char *) *3);
 for (i=0; i < 3; i++)
 {
  mysqlplayers[i]=malloc(12);
 }

 for (i=0; i < 3; i++)
 {
  strcpy(mysqlplayers[i], "bu");
 }

 for (i=0; i < 3; i++)
 {
  printf("%s\n", mysqlplayers[i]);
 }

 for (i=0; i < 3; i++){
  free(mysqlplayers[i]);
 }
 free(mysqlplayers);
 return (0);
}

Das tut was es soll.

Ich les' mir den Link nachher in Ruhe durch.

lilith2k3

Avatar von lilith2k3

Anmeldungsdatum:
14. Dezember 2006

Beiträge: 2999

Wohnort: OS

Okay, wieder was gelernt! Das Casting kann also eventuelle Probleme verdecken; auch wenn ich das malloc-Beispiel in dem Text ein wenig an den Haaren herbeigezogen finde. Wenn die Funktion einen falschen Rückgabewert liefert (wie in dem Beispiel angegeben, die "unbekannte" malloc-Funktion einen int) ist das Ergebnis selbstverständlich äußerst dubios und das Casting verdeckt das.
Insofern einverstanden.

Dann sollte eigentlich der Fehler im obigen Code von scosu nachwievor bei:

mysql_players[i] = (char*)malloc(500); 


liegen, oder?

Lunar

Anmeldungsdatum:
17. März 2006

Beiträge: 5792

lilith2k3 hat geschrieben:

Okay, wieder was gelernt! Das Casting kann also eventuelle Probleme verdecken; auch wenn ich das malloc-Beispiel in dem Text ein wenig an den Haaren herbeigezogen finde.

Ist es dir noch nie passiert, dass du irgendwo mal ein #include vergessen hast? 😉

lilith2k3

Avatar von lilith2k3

Anmeldungsdatum:
14. Dezember 2006

Beiträge: 2999

Wohnort: OS

Ist es dir noch nie passiert, dass du irgendwo mal ein #include vergessen hast?

Mir ist heute (s.o.) schlimmeres passiert *g*

Hello_World

Anmeldungsdatum:
13. Juni 2006

Beiträge: 3620

lilith2k3 hat geschrieben:

Dann sollte eigentlich der Fehler im obigen Code von scosu nachwievor bei:

mysql_players[i] = (char*)malloc(500); 


liegen, oder?

Wieso denn? Er allokiert doch Speicher, in den er später einen String kopieren will, daher sollte letzteres auch keine Probleme machen.

scosu

Anmeldungsdatum:
28. Juni 2008

Beiträge: 5

vielen dank für eure hilfe, also habe da nicht weiter geforscht woran es lag, sondern wie ihr gesagt habt umgeschrieben zu einem array von player structs und das funktionierte von anfang an wunderbar. und sieht natürlich jetzt auch schöner aus ☺. ich wusste garnicht dass das casten probleme machen kann, in einem tutorial stand, dass man es machen soll für kompatibilität zu c++ oder so, aber dann lasse ich das in zukunft lieber 😉

Hello_World

Anmeldungsdatum:
13. Juni 2006

Beiträge: 3620

Kompatbilität mit C++-Compilern ist überhaupt kein Argument. Wenn man C++ schreibt, dann allokiert man seinen Speicher mit new, nicht mit malloc. Wenn man C schreibt, dann gibt es keinen Grund für den Cast. Und wenn C-Funktionen von einem C++-Programm aus aufgerufen werden sollen, dann bindet man die mit extern "C" ein.