Programmlaufzeit (Stoppuhr) : warum funtioniert das Programm obwohl mein Array zu klein ist ??

#1
Hallo erst einmal an alle hier .
Ich befinde mich ebenfalls in einem C-Selbst-Lernen-Crash-Curs und bräuchte bitte einmal euer Fachwissen .

Zum Projekt : Programm soll Laufzeiten verschiedener Funktionen festhalten.

Mein Problem : Warum kann ich zeitsp[] in der main() mit beliebigen Wert benutzen ,
obwohl die Deklaration in zeit.c zu klein ist ?? Das dürfte doch nicht Funktionieren ?

/* zeit.c */
7: zeitspeicher zeitsp[0]; // WARUM KÖNNEN MEHR ZEITEN (in der main) GENOMMEN WERDEN ALS HIER DEKLARIERT ??

wenn ich schreibe :zeitspeicher zeitsp[];
bekomme ich eine Warnung vom gcc !


/* main.c */

18: zeitsp[0].start=zeit_mit_datum(); // HIER ist die Welt noch fast ok.
...
37: if (zeitsp[a].start == 0) // HIER WIRD ES KNIFFELIG es läuft mit jedem beliebigen Wert .



programmiert unter Ubuntu / Code:Blocks / und C .

C:
/* main.c */

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

#include "zeit.h"
#include "conio.h"

// Funktions Deklaration
void prognr(int);// Ausgabe Programm Status ( gestartet oder beendet )
void menu(void); // Hauptmenue
void programmende(void);// Hauptprogramm Ende - Ausgabe der gesamten Laufzeit

int main()
{
    int taste=0;
    printf("Hauptprogramm Start \n");
    zeitsp[0].start=zeit_mit_datum(); // HIER ist die Welt noch fast ok.
    menu(); // Aufruf Menue
    while ((taste = getch())) // Tasten Abfrage
    {
        switch(taste)
        {
            case 48: programmende();return 0;
            case 49: prognr(1);break;
            case 50: prognr(2);break;
            case 51: prognr(3);break;
            case 52: prognr(4);break;
        }
        menu();
    }
    return 0;
}

void prognr(int a) // Ausgabe Programm Status ( gestartet oder beendet )
{
    if (zeitsp[a].start == 0) // HIER WIRD ES KNIFFELIG es läuft mit jedem beliebigen Wert .
    {
        printf(" Programm %d gestartet : ",a);
        zeitsp[a].start=zeit_zeigen();           
    }
    else
    {
        printf(" Programm %d beendet : ",a);
        zeitsp[a].ende=zeit_zeigen();
        zeit_diff(a);
        zeitsp[a].start=0; // Zeitspeicher zurück setzen.
    }
}

void menu(void) // Hauptmenue
{
    printf("\n");
    for(int i=1;i<5;i++)
    {
        printf(" %d = Programm %d ",i,i);
        if (zeitsp[i].start == 0)
        {
            printf("starten \n");
        }
        else
        {
            printf("beenden \n");
        }
    }
    printf(" 0 = gesamtes Programm beenden \n\n");
}

void programmende(void) // Hauptprogramm Ende - Ausgabe der gesamten Laufzeit
{
    printf("Hauptprogramm beendet : ");
    zeitsp[0].ende=zeit_zeigen();
    zeit_diff(0);
}
C:
/* zeit.c */

#include <time.h>
#include <stdio.h>
#include "zeit.h"

zeitspeicher zeitsp[0]; // WARUM KÖNNEN MEHR ZEITEN GENOMMEN WERDEN ALS HIER DEKLARIERT ??

time_t zeit_nehmen() // Ausgabe : keine                (liefert Time(0) zurück)
{
    return time(0);
}

time_t zeit_zeigen(void) // Ausgabe : Zeit                 (liefert Time(0) zurück)
{
    time_t now;
    time(&now);
    struct tm *myTm;
    myTm = localtime(&now);
    printf("%02d:%02d:%02d Uhr \n", myTm->tm_hour, myTm->tm_min, myTm->tm_sec);
    return now;
    /*  int tm_sec;        // Sekunden
        int tm_min;        // Minuten
        int tm_hour;    // Stunden (0..23)
        int tm_mday;    // Monatstage (1..31)
        int tm_mon;        // Monate (0..11)
        int tm_year;    // Jahr (Kalenderjahr - 1900)
        int tm_wday;    // Wochentag (0..6, 0=Sonntag)
        int tm_yday;    // Tag im Jahr (0..365)
        int tm_isdst;    // Sommerzeit, 0=deaktiviert
    */
}
time_t zeit_mit_datum(void) // Ausgabe : Datum und Zeit    (liefert Time(0) zurück)
{
    time_t now;
    now = time(NULL);
    printf("%s\n", ctime(&now));
    return now;
}

void zeit_diff(int zeitnummer) // gibt verbrauchte Zeit in min und sec aus
{
    time_t zeit3=zeitsp[zeitnummer].ende-zeitsp[zeitnummer].start;
    int minuten=zeit3 / 60;
    int sekunden=zeit3-(minuten *60);
    printf("Laufzeit Programm : %d Min. %d Sec. \n",minuten,sekunden);
}
C:
/* zeit.h */

#ifndef ZEIT_H_INCLUDED
#define ZEIT_H_INCLUDED

typedef struct zeitspeicher
{
    time_t start;
    time_t ende;
}zeitspeicher;

zeitspeicher extern zeitsp[]; // Zeitspeicher

// Funktions Deklaration
time_t zeit_nehmen(void); // Ausgabe : keine                (liefert Time(0) zurück)
time_t zeit_zeigen(void); // Ausgabe : Zeit                 (liefert Time(0) zurück)
time_t zeit_mit_datum(void); // Ausgabe : Datum und Zeit    (liefert Time(0) zurück)

void zeit_diff(int zeitnummer); // gibt verbrauchte Zeit in min und sec aus

#endif // ZEIT_H_INCLUDED

GEBE mein conio.h dazu weil es zur Programm ausführung nötig ist.

C:
/* conio.h */

#ifndef CONIO_H_INCLUDED
#define CONIO_H_INCLUDED

// Funktions Deklaration
extern int getch(void); // liefert Zeichen Wert bei Tastendruck zurück OHNE ECHO ohne Return !
extern int getche(void); // liefert Zeichen Wert bei Tastendruck zurück MIT ECHO ohne Return !

#endif // CONIO_H_INCLUDED
C:
/* conio.c */

#include <termios.h>
#include <unistd.h>
#include <stdio.h>

int getch(void) // liefert Zeichen Wert bei Tastendruck zurück OHNE ECHO ohne Return !
{
    struct termios oldattr, newattr;
    int ch;
    tcgetattr( STDIN_FILENO, &oldattr );
    newattr = oldattr;
    newattr.c_lflag &= ~( ICANON | ECHO );
    tcsetattr( STDIN_FILENO, TCSANOW, &newattr );
    ch = getchar();
    tcsetattr( STDIN_FILENO, TCSANOW, &oldattr );
    return ch;
}

int getche(void) // liefert Zeichen Wert bei Tastendruck zurück MIT ECHO ohne Return !
{
    struct termios oldattr, newattr;
    int ch;
    tcgetattr( STDIN_FILENO, &oldattr );
    newattr = oldattr;
    newattr.c_lflag &= ~( ICANON );
    tcsetattr( STDIN_FILENO, TCSANOW, &newattr );
    ch = getchar();
    tcsetattr( STDIN_FILENO, TCSANOW, &oldattr );
    return ch;
}
Programm bei der Ausführung :
Code:
Hauptprogramm Start
Fri Mar 15 12:07:00 2019


1 = Programm 1 starten
2 = Programm 2 starten
3 = Programm 3 starten
4 = Programm 4 starten
0 = gesamtes Programm beenden

Programm 1 gestartet : 12:07:04 Uhr

1 = Programm 1 beenden
2 = Programm 2 starten
3 = Programm 3 starten
4 = Programm 4 starten
0 = gesamtes Programm beenden

Programm 2 gestartet : 12:07:21 Uhr

1 = Programm 1 beenden
2 = Programm 2 beenden
3 = Programm 3 starten
4 = Programm 4 starten
0 = gesamtes Programm beenden

Programm 2 beendet : 12:07:30 Uhr
Laufzeit Programm : 0 Min. 9 Sec.

1 = Programm 1 beenden
2 = Programm 2 starten
3 = Programm 3 starten
4 = Programm 4 starten
0 = gesamtes Programm beenden

Programm 1 beendet : 12:07:34 Uhr
Laufzeit Programm : 0 Min. 30 Sec.

1 = Programm 1 starten
2 = Programm 2 starten
3 = Programm 3 starten
4 = Programm 4 starten
0 = gesamtes Programm beenden

Hauptprogramm beendet : 12:07:42 Uhr
Laufzeit Programm : 0 Min. 42 Sec.
Ich hoffe ihr könnt mir helfen .
 
Zuletzt bearbeitet:

asc

Well-Known Member
c-b Experte
#3
C:
zeitspeicher zeitsp[0]; // WARUM KÖNNEN MEHR ZEITEN GENOMMEN WERDEN ALS HIER DEKLARIERT ??
Alleine diese Definition ist schon unfug. Du willst 0 zeitspeicher?

Nutze am besten bei GCC den -pedantic Flag. Dann kommt sowas gar nicht erst durch.

Dein Programm funktioniert vermutlich, weil auf zufällig nicht-verwendeten Speicher gezeigt wird.
Früher oder später wird dein Programm aber abstürzen.

Es ist nicht festgelegt, was bei Speicherüberläufen passieren soll (man spricht von "Undefiniertem Verhalten"), deswegen klappt das bis zu einem gewissen Grad (mal mehr, mal weniger, mal gar nicht). Vor allem bei C hat man hier viele Freiheiten bis es letztendlich zum Totalschaden kommt.

Da du ja mit Ubuntu entwickelst: Lass mal valgrind drüberlaufen ;)
 
#4
Danke für deine Analyse

Alleine diese Definition ist schon unfug. Du willst 0 zeitspeicher?
Der ursprüngliche wert war 3 . Also 3 geplante Zeitspeicher . zeitspeicher zeitsp[3]; . Habe dann noch 2 Zeiten dazugenommen aber Vergessen von 3 Zeitspeicher auf 5 Zeitspeicher zu erweitern . Das Programm lief also teste ich die Grenzen und stellte fest das es sogar mit meiner unsinn Deklaration funktionierte ... daher meine Frage .

Nutze am besten bei GCC den -pedantic Flag. Dann kommt sowas gar nicht erst durch.
Gut Ok ... das funktioniert mit zeitspeicher zeitsp[0]; ....
Aber nicht mit zeitspeicher zeitsp[3]; ... den in diesem Fall ist immer noch zwei Zeitspeicher zu wenig deklariert doch gcc sagt alles super !

Da du ja mit Ubuntu entwickelst: Lass mal valgrind drüberlaufen ;)
Oh interessant ... kenne ich mich zwar noch nicht mit aus, werde aber sofort ein blick drauf werfen ! NICE THX ^^
 
Zuletzt bearbeitet:
#5
Habe valgrind drüberlaufen lassen : egal ob zeitsp[0] oder zeitsp[2] erhalte ich folgende Meldung :

Code:
Hauptprogramm beendet : 20:18:17 Uhr
Laufzeit : 0 Min. 9 Sec.
==5401==
==5401== HEAP SUMMARY:
==5401==     in use at exit: 0 bytes in 0 blocks
==5401==   total heap usage: 20 allocs, 20 frees, 8,458 bytes allocated
==5401==
==5401== All heap blocks were freed -- no leaks are possible
==5401==
==5401== For counts of detected and suppressed errors, rerun with: -v
==5401== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Ich verstehe das also so : Das der Speicher für zeit 3 und 4 zwar benutzt wird aber in einem grossen Programm nicht sicher sind ... richtig ?

Oh ... je länger das Programm benutzt wird erhöht sich der heap speicher ... Ah also gibt es auf die Dauer eh ein Speicher überlauf !
danke nochmal für den valgrind tip !
 
Zuletzt bearbeitet:
#6
So ich noch einmal .
nach langem grübeln komme ich zum Schluss das dieses Programm eigentlich so aussehen musste :

C:
/* main.c */

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

#include "zeit.h"
#include "conio.h"

// Funktions Deklaration
void prognr(zeitspeicher *,int);// Ausgabe Programm Status ( gestartet oder beendet )
void menu(zeitspeicher *zeit,int); // Hauptmenue
void programmende(zeitspeicher *zeit);// Hauptprogramm Ende - Ausgabe der gesamten Laufzeit

int main()
{
    zeitspeicher zeitsp[5]= { 0 };
    int taste=0;
    printf("Hauptprogramm Start \n");
    zeitsp[0].start=zeit_mit_datum();

    for (int i1=1;i1<5;i1++)// Aufruf Menue
    {
        menu(&zeitsp[i1],i1);
    }
    printf(" 0 = gesamtes Programm beenden \n\n");

    while ((taste = getch())) // Tasten Abfrage
    {
        switch(taste)
        {
            case 48: programmende(&zeitsp[0]);return 0;
            case 49: prognr(&zeitsp[1],1);break;
            case 50: prognr(&zeitsp[2],2);break;
            case 51: prognr(&zeitsp[3],3);break;
            case 52: prognr(&zeitsp[4],4);break;
        }
        for (int i1=1;i1<5;i1++)// Aufruf Menue
        {
            menu(&zeitsp[i1],i1);
        }
        printf(" 0 = gesamtes Programm beenden \n\n");
    }
    return 0;
}

void prognr(zeitspeicher *zeit,int a) // Ausgabe Programm Status ( gestartet oder beendet )
{
    if (zeit->start == 0)
    {
        printf(" Programm %d gestartet : ",a);
        zeit->start=zeit_zeigen();
    }
    else
    {
        printf(" Programm %d beendet : ",a);
        zeit->ende=zeit_zeigen();
        zeit_diff(&zeit->start,&zeit->ende);
        zeit->start=0; // Zeitspeicher zurück setzen.
    }
}

void menu(zeitspeicher *zeit,int i) // Hauptmenue
{
    printf(" %d = Programm %d ",i,i);
    if (zeit->start == 0)
    {
        printf("starten \n");
    }
    else
    {
        printf("beenden \n");
    }
}

void programmende(zeitspeicher *zeit) // Hauptprogramm Ende - Ausgabe der gesamten Laufzeit
{
    printf("Hauptprogramm beendet : ");
    zeit->ende=zeit_zeigen();
    zeit_diff(&zeit->start,&zeit->ende);
}
C:
/* zeit.c */

#include <time.h>
#include <stdio.h>
#include "zeit.h"

//zeitspeicher zeitsp[5]; // WARUM KÖNNEN MEHR ZEITEN GENOMMEN WERDEN ALS HIER DEKLARIERT ??
// steht jetzt in der main !

time_t zeit_nehmen() // Ausgabe : keine                (liefert Time(0) zurück)
{
    return time(0);
}

time_t zeit_zeigen(void) // Ausgabe : Zeit                 (liefert Time(0) zurück)
{
    time_t now;
    time(&now);
    struct tm *myTm;
    myTm = localtime(&now);
    printf("%02d:%02d:%02d Uhr \n", myTm->tm_hour, myTm->tm_min, myTm->tm_sec);
    return now;
    /*  int tm_sec;        // Sekunden
        int tm_min;        // Minuten
        int tm_hour;    // Stunden (0..23)
        int tm_mday;    // Monatstage (1..31)
        int tm_mon;        // Monate (0..11)
        int tm_year;    // Jahr (Kalenderjahr - 1900)
        int tm_wday;    // Wochentag (0..6, 0=Sonntag)
        int tm_yday;    // Tag im Jahr (0..365)
        int tm_isdst;    // Sommerzeit, 0=deaktiviert
    */
}
time_t zeit_mit_datum(void) // Ausgabe : Datum und Zeit    (liefert Time(0) zurück)
{
    time_t now;
    now = time(NULL);
    printf("%s\n", ctime(&now));
    return now;
}

void zeit_diff(time_t *zeit1,time_t *zeit2) // gibt verbrauchte Zeit in min und sec aus
{
    time_t zeit3=zeit2-zeit1;
    int minuten=zeit3 / 60;
    int sekunden=zeit3-(minuten *60);
    printf(" Laufzeit : %d Min. %d Sec. \n",minuten,sekunden);
}
C:
/* zeit.h */

#ifndef ZEIT_H_INCLUDED
#define ZEIT_H_INCLUDED

typedef struct zeitspeicher
{
    time_t start;
    time_t ende;
}zeitspeicher;

//zeitspeicher extern zeitsp[]; // Zeitspeicher

// Funktions Deklaration
time_t zeit_nehmen(void); // Ausgabe : keine                (liefert Time(0) zurück)
time_t zeit_zeigen(void); // Ausgabe : Zeit                 (liefert Time(0) zurück)
time_t zeit_mit_datum(void); // Ausgabe : Datum und Zeit    (liefert Time(0) zurück)

void zeit_diff(time_t *zeit1,time_t *zeit2); // gibt verbrauchte Zeit in min und sec aus

#endif // ZEIT_H_INCLUDED

komischer weise für beides zum gleichen ergebnis !!
was meint ihr dazu ??


Lustig finde ich hierbei das dieses Programm auch läuft wenn ich in der main.c die Zeile 16 : in zeitspeicher zeitsp[1]= { 0 }; ändere
 
Oben