Erstes Programm: "Laufzeit"fehler und Projektidee



  • Das wird nichts, da der Aufruf der Funktionen (bei printf) innerhalb von einem Sequenzpoint liegen.

    Du weißt nicht, in welcher Reihenfolge und mit welchen Werten die Funktion swap aufgerufen wird. (hat a beim aufruf von b=... schon den Wert von a ?)

    Was erwartest du von der Zuweisung static int c = a; ?
    Die Zuweisung vom Wert von a bei jedem Aufruf? Dann brauchst du kein static.
    Die Zuweisung vom Wert von a beim ersten Aufruf? Dann kannst du die Funktion für nichts anderes mehr benutzen.



  • DirkB schrieb:

    Zudem startet man Konsolenprogramme auch in der offenen Konsole.

    Danke! Ich dachte schon, ich wäre der einzige, der das hier bei diesen Gelegenheiten immer rausschreit ...



  • .exe-Dateien sind natürlich dafür da, durch einen Doppelklick vom Anwender geöffnet zu werden, und das ohne vorherige Installation.

    Ihr scheint das Wort "einfach" noch nicht zu verstehen.



  • Äh, nein.
    Das mag für Programme für eine GUI gelten.

    Und es muss noch nicht einmal eine .exe sein.

    Wenn du ein Konsolenprogramm schreibst, benutze es in der Konsole.
    Sonst schreib eins für die GUI. Aber das ist dann nicht mehr so einfach (sonst würdest du es schon machen)



  • regInfo000? schrieb:

    .exe-Dateien sind natürlich dafür da, durch einen Doppelklick vom Anwender geöffnet zu werden, und das ohne vorherige Installation.

    Ihr scheint das Wort "einfach" noch nicht zu verstehen.

    Wie DirkB schon beschrieben hat, kommt das sehr auf das Programm an. Wenn es nur durchläuft, eine Ausgabe produziert und dann terminiert, wirst Du die Ausgabe nie zu sehen bekommen.
    Aber wenn Du schon alles so gut weißt, wie das hier klingt ... wieso stellst Du dann überhaupt noch irgendwelche Fragen?



  • So, ich weiß selbstverständlich, wie man die Konsole benutzt, denn ich kompiliere ja C-Programmtext darüber.

    Später ist es nervig, ein Programm immer über cmd.exe aufrufen zu müssen, bzw., wenn es nach der Eingabe sofort wieder schließt.

    Jetzt habe ich ein paar weitere Fragen und so etwas hier geschrieben:

    /*
     * Kommentar
     */
    
    #include <limits.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    typedef unsigned char char255; /* 0..255 */
    
    int swap(int *hahaha, int *b);
    
    int main(void) {
    	int a, b;
    	printf("!!Hello World!!\n");
    	printf("Bitte a und b (Ganzzahl) eingeben: ");
    	scanf("%i %i", &a, &b);
    
    	printf("a=%i, b=%i\n", a, b);
    
    	printf("a + b = %i\n",       a + b);
    	printf("a - b = %i\n",       a - b);
    	printf("a * b = %i\n",       a * b);
    	printf("a / (b | 1) = %i\n", a / (b | 1));
    	printf("a % (b | 1) = %i\n", a % (b | 1));
    	printf("b << 1 = %i\n",      b << 1);
    	printf("b >> 1 = %i\n",      b >> 1);
    
    	swap(&a, &b);
    	printf("a=%i, b=%i\n", a, b);
    
    	printf("a + b = %i\n",       a + b);
    	printf("a - b = %i\n",       a - b);
    	printf("a * b = %i\n",       a * b);
    	printf("a / (b | 1) = %i\n", a / (b | 1));
    	printf("a % (b | 1) = %i\n", a % (b | 1));
    	printf("b << 1 = %i\n",      b << 1);
    	printf("b >> 1 = %i\n",      b >> 1);
    
    	printf("b | 1 << sizeof(1) * 8 - 1 = %i\n", b | 1 << sizeof(1) * 8 - 1);
    	getchar();
    	getchar();
    	return EXIT_SUCCESS;
    }
    
    int swap(int *a, int *b) {
    	*a ^= *b ^= *a;
    	return 1;
    }
    
    C:\Users\MyName\Desktop>%gcc% HelloWorld.c
    HelloWorld.c: In function 'main':
    HelloWorld.c:40:2: warning: suggest parentheses around '-' inside '<<' [-Wparent
    heses]
      printf("b | 1 << sizeof(1) * 8 - 1 = %i\n", b | 1 << sizeof(1) * 8 - 1);
      ^
    
    C:\Users\MyName\Desktop>HelloWorld.exe
    !!Hello World!!
    Bitte a und b (Ganzzahl) eingeben: 123 234
    a=123, b=234
    a + b = 357
    a - b = -111
    a * b = 28782
    a / (b | 1) = 0
    a % (b | 1) = 123
    b << 1 = 468
    b >> 1 = 117
    a=234, b=145
    a + b = 379
    a - b = 89
    a * b = 33930
    a / (b | 1) = 1
    a % (b | 1) = 89
    b << 1 = 290
    b >> 1 = 72
    b | 1 << sizeof(1) * 8 - 1 = -2147483503
    
    C:\Users\MyName\Desktop>
    

    Er warnt, in Zeile 40 zu wenige runde Klammern gesetzt zu haben. Die Rangfolge der Operatoren habe ich einfach mal hierher entnommen: http://www.imb-jena.de/~gmueller/kurse/c_c++/c_operat.html , dort steht, dass der nicht geklammerte Ausdruck meiner Intention entspricht.

    1. Wie sollte geklammert werden?

    2. sizeof(1) , sizeof(b) oder sizeof(int) verwenden? (1 | 1 << sizeof(1) * 8 - 1 entspricht bei mir -(2^31)+1, das ist also korrekt.)

    3. int swap(int *hahaha, int *b); funktioniert nicht richtig. Ich habe mir nur a b a gemerkt, was ist an dem swap abgesehen des returns falsch?

    4. Kennt ihr eine Seite, auf der "typedef struct" gut erklärt wird?

    ( 5) Kennt jemand eine [url=Nichtproportionale Schriftarten (Dickten-/Festbreitschrift)]http://de.wikipedia.org/wiki/Liste_von_Schriftarten#Nichtproportionale_Schriftarten_.28Dickten-.2FFestbreitschrift.29[/url], die nicht so viel Platz wie "Courier New" benötigt? )



  • Wenn du nu nicht den Kernighan willst:
    http://openbook.galileocomputing.de/c_von_a_bis_z/

    Setze Klammern immer, auch wenn die Assoziativität deiner "Intention" entspricht. Ist besser lesbar und eindeutig. Wie das geht, weißt du doch sicher noch aus dem Mathe-Unterricht aus der 6. Klasse?
    (Ich hoffe ja, du willst nicht beruflich programmieren...)


  • Mod

    regInfo000? schrieb:

    int swap(int *a, int *b) {
    	*a ^= *b ^= *a;
    	return 1;
    }
    
    1. int swap(int *hahaha, int *b); funktioniert nicht richtig. Ich habe mir nur a b a gemerkt, was ist an dem swap abgesehen des returns falsch?

    Es fehlt noch eine weitere Zuweisung an *b.
    Abgesehen führt diese Schreibweise zu undefiniertem Verhalten (es sei denn, es wird ein C++11-Compiler eingesetzt).
    Dieses swap ist destruktiv, wenn ein Objekt mit sich selbst geswapped wird, ausserdem ist es (mit modernen Prozessorarchitekturen, es sei denn der Compiler ist sehr schlau) weniger effizient als normales 3-Wege-swap.

    Korrekt wäre

    int swap(int *a, int *b) {
            *b ^= *a;
            *a ^= *b;
            *b ^= *a;
    	return 1;
    }
    


  • fibeline schrieb:

    (Ich hoffe ja, du willst nicht beruflich programmieren...)

    Doch, das möchte ich später mal machen.

    Ich hab' jetzt mal eine Personalverwaltung wie folgt geschrieben:

    /*
     * Kommentar
     */
    
    #include <limits.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    enum Bereich { Management=30, Entwicklung=10, Produktion=1, Marketing=2, Vertrieb=1 };
    
    typedef struct {
    	char *name;
    	char *vorname;
    	unsigned int personalNummer;
    	enum Bereich abteilung;
    	float gehalt;
    	} Angestellter;
    
    Angestellter angestellte[10] = {
    	{ "aab", "aaa", 111, Vertrieb, 1111 },
    	{ "bbc", "bbb", 222, Marketing, 2222 },
    	{ "ccd", "ccc", 333, Produktion, 3333 },
    	{ "dde", "ddd", 444, Entwicklung, 4444 },
    	{ "Pan", "Peter", 555, Management, 9999 }
    };
    
    double durchschnitt(void) {
    	int i = 0;
    	double d = 0.0;
    	for (; i < 10; i++) {
    		d += angestellte[i].gehalt;
    	}
    	return d / 10.0;
    }
    
    void erhoeheGehalt(void) {
    	int i = 0;
    	for (; i < 10; i++) {
    		Angestellter *a = &angestellte[i];
    		a->gehalt *= a->abteilung / 100.0 + 1.0;
    	}
    }
    
    void drucke(Angestellter *ang) {
    	printf("%-10s%-10s%10i%10d%15f\n", (*ang).vorname, (*ang).name, (*ang).personalNummer, (*ang).abteilung, (*ang).gehalt);
    }
    
    void druckeAlle(void) {
    	int i = 0;
    	for (; i < 10; i++) {
    		drucke(&angestellte[i]);
    	}
    }
    
    int main(void) {
    	/* int a, b; */
    	druckeAlle();
    
    	printf("durchschnitt() = %f\n", durchschnitt());
    	erhoeheGehalt();
    	printf("durchschnitt() = %f\n", durchschnitt());
    
    	druckeAlle();
    	getchar();
    	return EXIT_SUCCESS;
    }
    

    Wie schreibe ich das ganze Ding jetzt so um, das ich 10 Array-Elemente oder ein dynamisch/es (wachsendes) Array/Feld benutzen kann?

    1. Wie scanf richtig benutzen?

    2. 4444.0F * (10 / 100.0 + 1.0) sollte 4888,4 ergeben, ergibt bei mir aber 4888,399902. Wie runde ich oder rechne genauer?

    3. Wie bekomme ich so eine schöne enum-Ausgabe hin, d. h., das da steht "Marketing" usw. usf. etc. pp.?

    Danke für eure Mitarbeit



  • regInfo000? schrieb:

    Wie schreibe ich das ganze Ding jetzt so um, das ich 10 Array-Elemente

    Sie erstmal zu, dass du die 5 vorhandenen richtig benutzt.
    Im Augenblick rechnest du mit Phantomdaten aus den Inizes 5 bis 9

    regInfo000? schrieb:

    oder ein dynamisch/es (wachsendes) Array/Feld benutzen kann?

    mit Zeigern und malloc

    regInfo000? schrieb:

    1. Wie scanf richtig benutzen?

    Referenz lesen und bei Problemen fragen.

    regInfo000? schrieb:

    1. 4444.0F * (10 / 100.0 + 1.0) sollte 4888,4 ergeben, ergibt bei mir aber 4888,399902. Wie runde ich oder rechne genauer?

    double nehmen. Bei Geldbeträgen rechnest du besser mit Ganzzahlen in Cent.

    regInfo000? schrieb:

    1. Wie bekomme ich so eine schöne enum-Ausgabe hin, d. h., das da steht "Marketing" usw. usf. etc. pp.?

    Selber machen. (mit Array oder switch/case ...)



  • Gut, danke erst mal.

    @DirkB: Warum meldest du dich denn hier nicht an (Registrierung), dann hast du doch sicherlich einige Vorteile, oder wurdest du in der vergangenheit mal "durch unfreundliches Verhalten vergrault/vertreiben"?

    Um auf dieser Ebene zu bleiben, und weil ich das andere Thema bzgl. Strings gelesen habe,

    wie kann ich ein/e String-Konstante/Literal verändern, oder wie lege ich veränderbare Zeichenketten in C an? Wie umgehe ich, dass String-Literale nicht während der gesamten Programmlaufzeit auf dem Stack, virtuellen Speicher, RAM/Festplatte o. Ä. liegen?

    Danke auch an dieser Stelle



  • regInfo000? schrieb:

    wie kann ich ein/e String-Konstante/Literal verändern,

    Verändern und Konstante widersprechen sich.

    regInfo000? schrieb:

    oder wie lege ich veränderbare Zeichenketten in C an?

    Array oder dynamischer Speicher (malloc)
    Du kannst bei der Definition von einem Array auch gleich ein Wert/Inhalt zuweisen.

    regInfo000? schrieb:

    Wie umgehe ich, dass String-Literale nicht während der gesamten Programmlaufzeit auf dem Stack, virtuellen Speicher, RAM/Festplatte o. Ä. liegen?

    Gar nicht. Irgendwo muss die Information stehen.



  • Wie schreibe ich "dies ist ein Täxt" in ein char []? (Sobald ich " " verwende, wird intern doch eine programmlebenslängliche Konstante angelegt, oder?) 💡



  • regInfo000? schrieb:

    Wie schreibe ich "dies ist ein Täxt" in ein char []? (Sobald ich " " verwende, wird intern doch eine programmlebenslängliche Konstante angelegt, oder?) 💡

    char foo[] = "ab";
    Ist das Gleiche wie:
    char foo[] = { 'a', 'b', '\0'};
    Da wird keine Konstante erstellt.



  • int bar(char *text)
    { char foo[10] = "ab"; 
    
      //mach etwas mit foo
    
    }
    

    Beim Auruf der Funktion wird dann "ab" in das Array kopiert. Es steht also irgendwo im Speicher.
    Wie willst du das verhindern? Bzw. was stört dich daran?



  • Sind Arrays automatische Variablen? Angenommen, ich lese eine mehrere mb Datei ein, möchte nach char [] oder char * "konvertieren", aber nicht sämtlichen Virtuellen Speicher benutzen..

    In Java ist das ganz einfach gewesen, Datei Zeile für Zeile lesen, "verarbeiten", Block/Gültigkeitsbereich/Scope verlassen oder Variable auf null setzen, und beim nächsten Durchlauf des GCs wird aufgeräumt..

    Siehe hier: http://de.wikipedia.org/wiki/Variable_(Programmierung)#Sichtbarkeitsbereich_von_Variablen_.28Scope.29

    1. Sind Structs oder sind deren Variablen automatische Variablen?


  • Ja, Arrays sind automatische Variablen,
    Automatische Variablen werden beim verlassen des Scopes, in dem sie definiert wurden, ungültig.

    Arrays kann man nach ihrer Definition nicht in der Größe ändern oder einen anderen Speicherplatz zuweisen. (sie wachsen nicht dynamisch - auch nicht statisch)
    Darum gibt es auch keine GC.

    Bei dynamischen Speicher sieht da anders aus. Aber da bist du (als Programmierer) für die Anforderung und Freigabe zuständig. Darum gibt es auch keine GC.*

    Ja, auch structs sind automatische Variablen (im Prinzip alles was einen Namen hat und Speicherplatz anbietet).
    Speicher von malloc hat keinen Namen, Stringliterale auch nicht.
    Ein Array hat einen Namen.

    *Mag sein das freie benachbarte Speicherblöcke wieder zusammengefasst werden.



  • Ok, ich hab' jetzt mal einen Binärbaum ohne löschen/Remove geschrieben, um malloc und struct kennenzulernen:

    /*
     * Kommentar
     */
    
    #include <limits.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    typedef struct Node {
    	char str[20];
    	struct Node *left;
    	struct Node *right;
    } Node;
    
    Node *tree = NULL;
    
    void cop1(char str[], Node *nod) {
    	int i;
    	for (i = 0; str[i] != '\0' && i < 19; i++)
    		nod->str[i] = str[i];
    	nod->str[i] = '\0';
    	nod->left = NULL;
    	nod->right = NULL;
    }
    
    void add1(char str[], Node *nod) {
    	if (nod->left == NULL || nod->right == NULL) {
    		Node *newNod = (Node *) malloc(sizeof(Node));
    		cop1(str, newNod);
    		if (nod->left == NULL)
    			nod->left = newNod;
    		if (nod->right == NULL)
    			nod->right = newNod;
    		return;
    	}
    	if (rand() % 2 == 0)
    		add1(str, nod->left);
    	else
    		add1(str, nod->right);
    }
    
    void add(char str[]) {
    	if (tree == NULL) {
    		tree = (Node *) malloc(sizeof(Node));
    		cop1(str, tree);
    		return;
    	}
    	add1(str, tree);
    }
    
    void printTree1(int ebe, Node *nod) {
    	if (nod == NULL)
    		return;
    	printf("%-5i%s%p%p\n", ebe, nod->str, nod->left, nod->right);
    	ebe++;
    	printTree1(ebe, nod->left);
    	printTree1(ebe, nod->right);
    }
    
    void printTree(void) {
    	printTree1(1, tree);
    }
    
    int main(void) {
    	int i;
    	int array[10];          /* Deklaration */
    	int *pointer1, *pointer2;
    	pointer1 = array;       /* pointer1 auf Anfangsadresse von array */
    	pointer2 = array + 3;   /* pointer2 auf 4.Element von array      */
    
    	array[0]      = 99;    /* array[0] */
    	pointer1[1]   = 88;    /* array[1] */
    	*(pointer1+2) = 77;    /* array[2] */
    	*pointer2     = 66;    /* array[3] */
    
    	for (i = 0; i < 10; i++)
    		printf("%5i\n", array[i]);
    
    	add("eins");
    	add("Zwei");
    	add("drei");
    	add("Vier");
    	add("fuenf");
    	add("Sechs");
    	add("sieben");
    	add("Acht");
    	add("neun");
    	add("Sehr laaannngggeeer String/Zeichenkette!!");
    	printTree();
    
    	getchar();
    	return EXIT_SUCCESS;
    }
    

    Der BinTree wird zufällig befüllt (damit entsteht auch keine Liste).

    1. Warum muss ich typedef struct Node .... Node schreiben? Dieses Node ist doppelt. Aber ohne müsste ich immer (struct Node 😉 schreiben, wieso?

    2. Die Ausgabe (Wurzel-Links-Rechts / dfs) dreht total durch bei mir, was habe ich vergessen?

    3. Ist string copy richtig, wenn ich in der Struct immer Zeichenketten mit genau 20 Zeichen (inklusive '\n') haben möchte?

    4. Wieso kann ich
      struct Node *left = NULL;
      nicht schreiben?

    5. Wie kann ich relativ einfach eine Breitensuche hinbekommen?

    Danke noch mal für Antworten

    PS. Zeile 65 bis 74 habe ich einer anderen Quelle (c_von_a_bis_z) entnommen und gehört eig. nicht zum Programm. (Nicht verwirren lassen)



  • regInfo000? schrieb:

    1. Warum muss ich typedef struct Node .... Node schreiben? Dieses Node ist doppelt. Aber ohne müsste ich immer (struct Node 😉 schreiben, wieso?

    Das ist C-Syntax.

    regInfo000? schrieb:

    1. Die Ausgabe (Wurzel-Links-Rechts / dfs) dreht total durch bei mir, was habe ich vergessen?

    Du trägst bei add1 den neuen Node links und rechts ein.

    regInfo000? schrieb:

    1. Ist string copy richtig, wenn ich in der Struct immer Zeichenketten mit genau 20 Zeichen (inklusive '\n') haben möchte?

    string copy kenne ich nicht. Interresanter wäre auch das '\0'

    regInfo000? schrieb:

    1. Wieso kann ich
      struct Node *left = NULL;
      nicht schreiben?

    Weil du eine Wertzuweisung nur bei der Definition der Variablen machen kannst. Dazu gehört aber nicht typedef.
    Du kannst bei der Definition die Werte übergeben:

    Node knoten = {"", NULL, NULL);
    

    oder wenn es dynamisch werden soll, nimm calloc.



  • Allerdings Platz für ein 20-elemntiges Array wird in der Struct bzw. bei malloc angelegt.

    if (nod->left == NULL)
                nod->left = newNod;
            else if (nod->right == NULL)
                nod->right = newNod;
    /*....*/
    	printf("%-5i%-19s%7p%7p%7p\n", ebe, nod->str, nod, nod->left, nod->right);
    

    funktioniert.

    Kann ich

    if (nod->left == NULL || nod->right == NULL) {
    

    umschreiben in

    if (nod == NULL) {
    

    und dann &nod "etwas neues" zuweisen?

    Verwendet ihr auch den -> für (*variable).element ?


Anmelden zum Antworten