PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : C: Seg. Fault trotz reibungsfreier Übersetzung



xzm
01-04-2008, 23:09
Hallo!
Ich bin Anfänger in C und arbeite mich erst langsam ein, daher kann es sein, dass die Probleme die ich habe trivial sind. Ich probiere zur Zeit ein wenig mit sytem()-Befehlen herum, daher wollte ich mir ein Programm schreiben, das mir den exitstatus eines Befehls zurückgibt, da dies ja nicht bei jedem Programm in der man-Page angegeben ist und ich so besser mit den programmen arbeiten kann.

nun, das Programm sieht so aus:

/* exitstatus.c
* gibt den exitstatus eines systembefehls zurück */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]) {
int len = strlen(*argv);
char cmd[len];
int i;
for(i = 1; i <= argc; i++) {
strcat(cmd, argv[i]);
}
int es = system(cmd);
printf("%s gab %i zurueck!",cmd,es);
exit(0);
}


soweit so gut, schreit wenn ich einen groben schnitzer gebaut habe ;)

beim kompillieren läuft auch mit -Wall alles glatt:

xzm@staatsterror:~$ gcc -Wall exitstatus.c -o exitstatus
xzm@staatsterror:~$

dennoch bekomm ich einen Seg. Fault:

xzm@staatsterror:~$ ./exitstatus
Segmentation fault (core dumped)
xzm@staatsterror:~$


Was mach ich falsch? Isses die ausführung oder ist der Grundgedanken falsch?

Danke für die Hilfe!

lokicall
02-04-2008, 07:26
Erstmal bei strlen wird \0 nicht berücksichtigt und
zweitens

int len = strlen(*argv);
char cmd[len];
int i;
for(i = 1; i <= argc; i++) {
strcat(cmd, argv[i]);
}

Reicht der Platz für cmd auch für alle argv aus?

xzm
02-04-2008, 09:59
Erstmal bei strlen wird \0 nicht berücksichtigt und
zweitens

int len = strlen(*argv);
char cmd[len];
int i;
for(i = 1; i <= argc; i++) {
strcat(cmd, argv[i]);
}

Reicht der Platz für cmd auch für alle argv aus?

mhh, genau deshalb wollte ich das vorher mittels len feststellen, wielang *argv ist. das klappt auch komischer weise, d.h. ich bekomme wenn ich nach len nen printf einfüge die richtige anzahl von zeichen, dennoch bricht es praktisch bei der whileschleife ab.

wegen \0:

int len = strlen(*argv);
len++;
char cmd[len];

wäre besser, oder? da ja dann noch platz für \0 ist.

ContainerDriver
02-04-2008, 13:05
@xzm:
wie schon von lokicall angesprochen: mit


int len = strlen(*argv);

bekommst du nur die Länge des Strings, der in argv[0] steht (die Aufrufe strlen(*argv) und strlen(argv[0]) sind äuqivalent). Die richtige Länge kannst berechnen, in dem du alle Argumente durch gehst.

In deiner Schleife


for(i = 1; i <= argc; i++)

gehst du ein Element zu weit.

Bei einem Aufruf von


./programm arg1 arg2

ist argc = 3 und die Argumente (+ Programmname) finden sich in dem Array argv an den Stellen mit den Indizes 0 - 2.

Gruß, Florian

xzm
02-04-2008, 13:26
hum, ich bin im mom so weit:

/* exitstatus.c
* gibt den exitstatus eines systembefehls zurück */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]) {
int i;
int len = 0;
for(i = 1; i < argc; i++) {
len += strlen(argv[i]);
}
char cmd[len];
for(i = 1; i < argc; i++) {
strcat(cmd, argv[i]);
strcat(cmd, " ");
printf("%s", cmd);
}
int es = system(cmd);
printf("%s gab %i zurueck!\n",cmd,es);
exit(0);
}


gibt mir wenigstens kein segfault mehr zurück, wenn ich ./exitstatus einfach so angebe, gibt er mir (da er ja keinen parameter hat) 0 zurück, wie es sein sollte, wenn ich aber irgendwas dahinterhäng (zB ping) klappt es nicht.
was mach ich falsch?

EDIT: ich glaube es liegt an der strcat(cmd, " "); zeile, vllt kommt er damit nicht klar, obwohl " " doch eigentlich umgewandelt werden müsste, oder?

ContainerDriver
02-04-2008, 13:34
Also, du hast die Größe von cmd bzw. len falsch berechnet und cmd nicht initialisiert.



/* exitstatus.c
* gibt den exitstatus eines systembefehls zurück */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]) {
int i;
int len = 0;
if (argc==1)
{
printf("Kein Argument angegeben!\n");
exit(1);
}
for(i = 1; i < argc; i++) {
len += strlen(argv[i]) + 1; // +1 wegen " " weiter unten
}
len++; //Nullbyte
char cmd[len];
cmd[0]='\0'; //Initialisierung
for(i = 1; i < argc; i++) {
strcat(cmd, argv[i]);
strcat(cmd, " ");
printf("%s\n", cmd);
}
int es = system(cmd);
printf("%s gab %i zurueck!\n",cmd,es);
exit(0);
}


Beachte, dass du nach dem C-Standard nur Variablen ganz am Anfang des Funktionskopfs definieren darfst! Der gcc (bzw. der Kompiler, den du verwendest) übersetzt den Code zwar, aber wenn du das z.B. im Visual C Studio übersetzen willst, geht das nicht.

xzm
02-04-2008, 13:53
Also, du hast die Größe von cmd bzw. len falsch berechnet und cmd nicht initialisiert.



/* exitstatus.c
* gibt den exitstatus eines systembefehls zurück */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]) {
int i;
int len = 0;
if (argc==1)
{
printf("Kein Argument angegeben!\n");
exit(1);
}
for(i = 1; i < argc; i++) {
len += strlen(argv[i]) + 1; // +1 wegen " " weiter unten
}
len++; //Nullbyte
char cmd[len];
cmd[0]='\0'; //Initialisierung
for(i = 1; i < argc; i++) {
strcat(cmd, argv[i]);
strcat(cmd, " ");
printf("%s\n", cmd);
}
int es = system(cmd);
printf("%s gab %i zurueck!\n",cmd,es);
exit(0);
}


Beachte, dass du nach dem C-Standard nur Variablen ganz am Anfang des Funktionskopfs definieren darfst! Der gcc (bzw. der Kompiler, den du verwendest) übersetzt den Code zwar, aber wenn du das z.B. im Visual C Studio übersetzen willst, geht das nicht.

ah, so langsam kapier ich meinen fehler... aber, müsste

len += strlen(argv[i]) + 1; nicht
len += strlen(argv[i]) + (argc-1)heißen, da ich ja pro argument ein leerzeichen einfüge?

ContainerDriver
02-04-2008, 14:13
Nein, da du ja alle Argumente durch gehst, musst du jeweils nur +1 rechnen. Mit


len += strlen(argv[i]) + (argc-1)

wäre len um (argc-1)*(argc-2) zu groß!

xzm
02-04-2008, 14:16
Nein, da du ja alle Argumente durch gehst, musst du jeweils nur +1 rechnen. Mit


len += strlen(argv[i]) + (argc-1)

wäre len um (argc-1)*(argc-2) zu groß!
argh, hast recht -.-
# wheris mybrain ....