The Art of Work in C - Fragen zu typedef , Speicher Reservierung,Pointern und der Entwicklung modular verwendbarer Unterprogramme.

German

Well-Known Member
c-b Experte
#41
Da kannst du mal sehen, wie sehr man sich auf seinen eigenen Stil einschießen kann. Ich bin so auf Allman Einrückungen geprägt, dass ich die Schleife glatt übersehen hatte :oops:

Du wirst lachen aber darüber hatte ich mir auch schon Gedanken gemacht.
Hehe. Das ist natürlich nur ein Debugging Feature. Wenn jemand deine Lib in einem Programm nutzt, hilft dem Endnutzer ein verlorener Pointerwert nichts mehr.

Das mit den Beiden Aufruf - Befehlen
Jetzt hast du mich verloren. Was meinst du?
 

Eldarius

Well-Known Member
#42
Hehe. Das ist natürlich nur ein Debugging Feature.
Aber extrem nettes Feature . Als Anfänger hätte ich mir bestimmt einen "Wolf" getippt weil ich versucht hätte eine eigene Funktion zu schreiben.

Jetzt hast du mich verloren. Was meinst du?
C:
matrix *matrix_2 = MatrixCreate(lines2, columns2, sizeof(int));
    int **arr_2 = (int**)matrix_2->matrix_ptr;
Diese Beiden meine ich .

EDIT : in einem rutsch Daten und Array erstellen und dann das Array getrennt zu Verfügung zu stellen ... top ! Eine Menge Fehler der alten matric.c sind somit Geschichte .
 

German

Well-Known Member
c-b Experte
#43
Ach so. Naja, du hast damit den Pointer auf das Listenelement. Macht das Suchen und Löschen in der Liste etwas einfacher. Wenn du das Löschen der Liste dem atexit() überlassen willst, kannst du aber immer noch abkürzen:
int **arr_2 = (int**)MatrixCreate(lines_2, columns_2, sizeof(int))->matrix_ptr;
ABER du verbaust dir damit die Chance auf Rückgabewert NULL zu prüfen und das Programm geht in jedem Fall mit Segfault krachen, wenn eine Speicherallokation fehlschlägt.
 

Eldarius

Well-Known Member
#44
Macht das Suchen und Löschen in der Liste etwas einfacher
Habe ich schon bemerkt ... alles sehr viel einfacher ! Jetzt verstehe ich aber auch wenn du sagst ich denke zu kompliziert.

du verbaust dir damit die Chance auf Rückgabewert NULL zu prüfen
Ja das sehe ich auch so . Finde die Lösung mit 2 Befehlen auf jeden Fall besser ! Ich meine mal gelesen zu haben das man alles beliebig Schachteln kann ... aber hier erkennt man auch mal die Vorteile wenn es nicht gemacht wird .

Die Wichtigkeit auf NULL prüfen zu können ist mir durch Dich auch sehr klar geworden ! Das hat mir bis jetzt viel Ärger erspart.

EDIT : PS :
Ich hoffe übrigens dass die Verkettung der Liste okay ist. Habe das nicht ausgiebig getestet.
ich kann dich beruhigen ;)

Code:
Zeige Gespeicherte Matrix-Daten an:
Array Adresse : 0x5592bfdb7290 - 4 x 5  / Listen Adresse : 0x5592bfdb72c0
Array Adresse : 0x5592bfdb7770 - 3 x 8  / Listen Adresse : 0x5592bfdb7790
Array Adresse : 0x5592bfdb7840 - 5 x 6  / Listen Adresse : 0x5592bfdb7870
Array Adresse : 0x5592bfdb7950 - 6 x 7  / Listen Adresse : 0x5592bfdb7990
Array Adresse : 0x5592bfdb7a40 - 7 x 4  / Listen Adresse : 0x5592bfdb7a80
MatrixFree Adresse : 0x5592bfdb72c0  4 x 5
davor addr. : (nil) danach : 0x5592bfdb7790
MatrixFree Adresse : 0x5592bfdb7790  3 x 8
davor addr. : 0x5592bfdb72c0 danach : 0x5592bfdb7870
MatrixFree Adresse : 0x5592bfdb7870  5 x 6
davor addr. : 0x5592bfdb7790 danach : 0x5592bfdb7990
MatrixFree Adresse : 0x5592bfdb7990  6 x 7
davor addr. : 0x5592bfdb7870 danach : 0x5592bfdb7a80
MatrixFree Adresse : 0x5592bfdb7a80  7 x 4
davor addr. : 0x5592bfdb7990 danach : (nil)
 
Zuletzt bearbeitet:

German

Well-Known Member
c-b Experte
#46
Ja ich weiß. Der Witz ist, das die C-Runtime Bibliothek von Windows das z kennt. Ist auch in der Funktionsreferenz für printf bei Microsoft gelistet. Lediglich MinGW meckert es an, was ein Bug vom Compiler ist.
 

Eldarius

Well-Known Member
#47
@ German

Tut mir leid ... werde wohl noch ein bisschen brauchen mit der Analyse .
Es stockt weil die Lösch-Funktion nicht mit der MatrixInformation(); zusammen läuft .
Die erstellten Arrays werden zwar gelöscht aber verschwinden nicht aus der Auflistung .
Werde noch ein bisschen Knobeln und versuchen es selbst hin zu bekommen

Code:
list-head : (nil)  list-tail : (nil)
Array 0x55df26d53290 - 4 x 5 erstellt
gesuchte Adressen: 0x55df26d53260 - 0x55df26d53290 - 0x55df26d532c0
list-head : 0x55df26d532c0  list-tail : 0x55df26d532c0

Zeige Gespeicherte Matrix-Daten an:
Array Adresse : 0x55df26d532c0 = 4 x 5
Listen Adresse : 0x55df26d53290 davor addr. : (nil) danach : (nil)

list-head : 0x55df26d532c0  list-tail : 0x55df26d532c0
Lösche Addr: 0x55df26d53260 - 0x55df26d53290 - 0x55df26d532c0
list-head : 0x55df26d532c0  list-tail : 0x55df26d532c0
 sollten eigendlich jetzt NULL sein da das einzige Array gelöscht wurde

Zeige Gespeicherte Matrix-Daten an:
Array Adresse : 0x55df26d532c0 = 94416917573648 x 5
Listen Adresse : 0x55df26d53290 davor addr. : (nil) danach : (nil)
 Daten Speicher nicht Leer !
 

German

Well-Known Member
c-b Experte
#48
Gibst du die Daten nur frei, oder setzt du nach Freigabe die Pointervariablen auch auf NULL? Ins Blaue geschossen - Wenn head und tail denselben Pointerwert haben und das der gesuchte Wert ist, dann mach deine Speicherfreigabe und setze head und tail auf NULL.
 
Zuletzt bearbeitet:

Eldarius

Well-Known Member
#49
Guten Morgen ...

Gibst du die Daten nur frei, oder setzt du nach Freigabe die Pointervariablen auch auf NULL? Ins Blaue geschossen - Wenn head und tail denselben Pointerwert haben und das der gesuchte Wert ist, dann mach deine Speicherfreigabe und setze head und tail auf NULL.
head und tail hatten NULL nicht angenommen ... behielten einfach den 1. installierten Wert .
Naja habe bis zum Umfallen rumspielt . : Hatte beide an der falschen Stelle Auf NULL gesetzt . Mein Fehler !
Habe das gerade gefixt und werde mal weiter machen ... will deine For Schleife noch mal genau unter die Lupe nehmen .

Code:
list-head : (nil)  list-tail : (nil)
Array 0x56323a26f290 - 4 x 5 erstellt
gesuchte Adressen: 0x56323a26f260 - 0x56323a26f290 - 0x56323a26f2c0
list-head : 0x56323a26f2c0  list-tail : 0x56323a26f2c0

Zeige Gespeicherte Matrix-Daten an:
Array Adresse : 0x56323a26f2c0 = 4 x 5
Listen Adresse : 0x56323a26f290 davor addr. : (nil) danach : (nil)

list-head : 0x56323a26f2c0  list-tail : 0x56323a26f2c0
Lösche Addr: 0x56323a26f260 - 0x56323a26f290 - 0x56323a26f2c0

Keine Daten gespeichert.
 
Zuletzt bearbeitet:

Eldarius

Well-Known Member
#50
Hatte ja versprochen Heute die Lösch-Funktion rein zu stellen. Dicke Augen ich hab , doch das coding-board ist mit mir ... Meister .


C:
// matrix.h

#ifndef MATRIX_H_INCLUDED__
#define MATRIX_H_INCLUDED__
#include <stddef.h>

typedef struct matrix
{
    void *matrix_ptr; // eigentlich <Typ>** statt void*, aber so kann man typunabhängig bleiben und die Adresse genügt uns
    size_t lines;
    size_t columns;
    struct matrix *previous;
    struct matrix *next;
} matrix;

matrix *MatrixCreate(const size_t lines, const size_t columns, const size_t element_size);
matrix *MatrixFree(const matrix* matrixptr);
void MatrixVerbose(const int enable_message);
void MatrixInformation(void);

#endif // MATRIX_H_INCLUDED__
C:
// matrix.c

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


struct matrix_list
{
    matrix *head; // Anfang der Liste
    matrix *tail; // Ende der Liste
    int print_msg; // Flag für die Ausgabe (an: ungleich 0, aus: gleich 0)
};


// keine globalen Variablen ;-)
struct matrix_list *GetMatrixList(void)
{
    static struct matrix_list list;
    return &list;
}

// Callbackfunktion für atexit() um reservierten Speicher freizugeben, wenn das Programmende erreicht ist.
void KillList(void)
{
    struct matrix_list *list = GetMatrixList();
    matrix *mtrx = list->head;
    while (mtrx != NULL)
    {
        matrix *tmp = mtrx->next;
        char **lns = (char**)mtrx->matrix_ptr;
        free(*lns);
        free(lns);
        free(mtrx);
        mtrx = tmp;
    }
}

// Hier wird neben der Zeilen- und Spaltenzahl auch die Größe der Elemente übergeben, um typunabhängig zu bleiben
matrix *MatrixCreate(const size_t lines, const size_t columns, const size_t element_size)
{
    static int atexit_called; // statisch, um den Wert auch nach Rückgabe zu behalten.

    char *mem = (char*)calloc(lines * columns, element_size);
    char **lns = (char**)malloc(lines * sizeof(char*));
    matrix *new_mtrx = calloc(1, sizeof(matrix));

    if (mem == NULL || lns == NULL || new_mtrx == NULL)
    {


    if (GetMatrixList()->print_msg) // vielleicht am einfachsten es jeweils direkt in die jeweilige Funktion zu bringen ...
        fputs("Memory allocation failed.\n", stderr);

    return NULL;
    }

    for (char *it_mem = mem, **it_lns = lns, **lns_end = lns + lines; it_lns < lns_end; it_mem += element_size * columns, ++it_lns)
    {
        *it_lns = it_mem;
    }
    struct matrix_list *list = GetMatrixList();

    if (list->head == NULL)
        list->head = new_mtrx;

    new_mtrx->matrix_ptr = (void*)lns;
    new_mtrx->lines = lines;
    new_mtrx->columns = columns;
    if (list->tail != NULL)
        list->tail->next = new_mtrx;

    new_mtrx->previous = list->tail;
    list->tail = new_mtrx;

    if (atexit_called == 0) // falls atexit noch nicht aufgerufen wurde
    {
        atexit_called = 1;
        atexit(KillList);
    }
    if (GetMatrixList()->print_msg)
        printf("Array %p - %ld x %ld erstellt\n",new_mtrx->matrix_ptr,new_mtrx->lines,new_mtrx->columns);

    return new_mtrx;
}
void MatrixInformation(void)// Listet alle gespeicherten Arrays auf. ( Keine Bildschirmsteuerung ! )
{
    struct matrix_list *info = GetMatrixList();
    matrix *mtrx = info->head;
    if (mtrx != NULL){
        printf("Zeige Gespeicherte Matrix-Daten an:\n");
        while(mtrx != NULL){
            printf("Array-Adress : %p = %zu x %zu\n",mtrx,mtrx->lines,mtrx->columns);
            mtrx = mtrx->next;}
    }else{fputs("Keine Daten gespeichert.\n",stderr);}
}
void MatrixKill(matrix *matrixptr)
{
    if (GetMatrixList()->print_msg){
        printf("Lösche Array : %p = %zu x %zu\n",matrixptr,matrixptr->lines,matrixptr->columns);
        //printf("davor : %p   danach : %p\n",matrixptr->previous,matrixptr->next);
    }
    char **lns = (char**)matrixptr->matrix_ptr;
    matrixptr->columns=0;
    matrixptr->lines=0;
    matrixptr->matrix_ptr=NULL;
    matrixptr->next=NULL;
    matrixptr->previous=NULL;
    free(*lns);
    free(lns);
    free(matrixptr);
}
matrix *MatrixFree(const matrix* matrixptr)
{
    struct matrix_list *list = GetMatrixList();
    matrix *mtrx = list->head;
    matrix *mtrx2 = list->tail;
    matrix *mtrx1;
    if(list->head != NULL)
    {
        if(list->head == matrixptr)
        {
            if (mtrx->next == NULL)
            {
                    list->head = NULL;
                    list->tail = NULL;
                    MatrixKill(mtrx);
                    return NULL;
            }
            mtrx1 = list->head = mtrx->next;
            mtrx1->previous = NULL;
            MatrixKill(mtrx);
            return NULL;
        }
        else if(list->tail == matrixptr)
        {
            list->tail = mtrx2->previous;
            list->tail->next = NULL;
            MatrixKill(mtrx2);
            return NULL;
        }
        else
        {
            while(mtrx->next != NULL)
            {
                if(mtrx == matrixptr)
                {
                    mtrx1 = mtrx->previous;
                    mtrx2 = mtrx->next;
                    mtrx1->next = mtrx2;
                    mtrx2->previous = mtrx1;
                    MatrixKill(mtrx);
                    break;
                }
                mtrx = mtrx->next;
            }
            return NULL;
        }
        if (GetMatrixList()->print_msg)
            fputs("Array not in Memory allocatet .\n", stderr);
        return mtrx;
    }
    if (GetMatrixList()->print_msg)
        fputs("No Array in Memory-Data.\n", stderr);
    return mtrx;
}
// Flag für die Ausgabe setzen
void MatrixVerbose(const int enable_message)
{
    GetMatrixList()->print_msg = enable_message;
}
Ein kleiner Test dazu :
C:
// main.c

#include <stdio.h>
#include "matrix2.h"

int main(void)
{
    MatrixVerbose(0);
    MatrixInformation();
    size_t lines = 4, columns = 5;
    matrix *matrix_1 = MatrixCreate(lines, columns, sizeof(short));
    short **arr_1 = (short**)matrix_1->matrix_ptr;
    size_t lines2 = 3, columns2 = 8;
    matrix *matrix_2 = MatrixCreate(lines2, columns2, sizeof(int));
    int **arr_2 = (int**)matrix_2->matrix_ptr;
    size_t lines3 = 5, columns3 = 6;
    matrix *matrix_3 = MatrixCreate(lines3, columns3, sizeof(long));
    long **arr_3 = (long**)matrix_3->matrix_ptr;
    size_t lines4 = 6, columns4 = 7;
    matrix *matrix_4 = MatrixCreate(lines4, columns4, sizeof(int));
    MatrixInformation();
    puts("");

    int **arr_4 = (int**)matrix_4->matrix_ptr;

    for(size_t i = 0, k = 1 ; i < lines ; ++i)
    for(size_t j = 0 ; j < columns ; ++j, ++k)
        arr_1[i][j] = k;
    for(size_t i = 0; i < lines ; ++i)
    {
      for(size_t j = 0; j < columns; ++j)
    printf("%2hd ", arr_1[i][j]);
    puts("");
    }
    puts("");

    MatrixVerbose(1);
    matrix_2=MatrixFree(matrix_2);
    puts("");
    MatrixInformation();
    puts("");
    matrix_4=MatrixFree(matrix_4);
    puts("");
    MatrixInformation();
    puts("");
    matrix_3=MatrixFree(matrix_3);
    puts("");
    MatrixInformation();
    puts("");

    size_t lines5 = 7, columns5 = 4;
    matrix *matrix_5 = MatrixCreate(lines5, columns5, sizeof(int));
    int **arr_5 = (int**)matrix_5->matrix_ptr;
    puts("");
    MatrixInformation();
    puts("");

    MatrixFree(matrix_5);
    puts("");
    MatrixInformation();
    puts("");
    matrix_1=MatrixFree(matrix_1);
    puts("");
    MatrixInformation();
    puts("");
    return 0;
}
und jetzt noch die Bildschirmausgabe dazu :
Code:
Zeige Gespeicherte Matrix-Daten an:
Array-Adress : 0x5603c7b412c0 = 4 x 5
Array-Adress : 0x5603c7b41380 = 3 x 8
Array-Adress : 0x5603c7b414e0 = 5 x 6
Array-Adress : 0x5603c7b41600 = 6 x 7

 1  2  3  4  5
 6  7  8  9 10
11 12 13 14 15
16 17 18 19 20

Lösche Array : 0x5603c7b41380 = 3 x 8

Zeige Gespeicherte Matrix-Daten an:
Array-Adress : 0x5603c7b412c0 = 4 x 5
Array-Adress : 0x5603c7b414e0 = 5 x 6
Array-Adress : 0x5603c7b41600 = 6 x 7

Lösche Array : 0x5603c7b41600 = 6 x 7

Zeige Gespeicherte Matrix-Daten an:
Array-Adress : 0x5603c7b412c0 = 4 x 5
Array-Adress : 0x5603c7b414e0 = 5 x 6

Lösche Array : 0x5603c7b414e0 = 5 x 6

Zeige Gespeicherte Matrix-Daten an:
Array-Adress : 0x5603c7b412c0 = 4 x 5

Array 0x5603c7b415c0 - 7 x 4 erstellt

Zeige Gespeicherte Matrix-Daten an:
Array-Adress : 0x5603c7b412c0 = 4 x 5
Array-Adress : 0x5603c7b41ac0 = 7 x 4

Lösche Array : 0x5603c7b41ac0 = 7 x 4

Zeige Gespeicherte Matrix-Daten an:
Array-Adress : 0x5603c7b412c0 = 4 x 5

Lösche Array : 0x5603c7b412c0 = 4 x 5

Keine Daten gespeichert.
 

German

Well-Known Member
c-b Experte
#51
C:
void MatrixKill(matrix *matrixptr)
{
  if (GetMatrixList()->print_msg)
  {
    printf("Lösche Array : %p = %zu x %zu\n", matrixptr, matrixptr->lines, matrixptr->columns);
    //printf("davor : %p   danach : %p\n",matrixptr->previous,matrixptr->next);
  }
  char **lns = (char**)matrixptr->matrix_ptr;
  //matrixptr->columns = 0;
  //matrixptr->lines = 0;
  //matrixptr->matrix_ptr = NULL;
  //matrixptr->next = NULL;
  //matrixptr->previous = NULL;
  free(*lns);
  free(lns);
  free(matrixptr); // hier werden alle Werte ungültig die du zuvor mühselig genullt hast
}
Ich hatte mit meiner Bemerkung tatsächlich nur auf head und tail abgezielt, denn die musst du jeweils überprüfen. Wenn du ein Element aus der Liste löscht, musst du nichts nullen. Dieses Element fliegt sowieso aus der Liste. Sollte mit einem im Programm gespeicherten Pointerwert versucht werden noch darauf zuzugreifen, hilft es trotzdem nicht die Werte vorher zu nullen. Du würdest auf einen freigegebenen und somit ungültigen Speicherbereich zugreifen, was in die Hose geht.
 

Eldarius

Well-Known Member
#52
Sollte mit einem im Programm gespeicherten Pointerwert versucht werden noch darauf zuzugreifen, hilft es trotzdem nicht die Werte vorher zu nullen.
Uhi ... stimmt ... habe die Altlast vom Testen vergessen .Die Zeilen 9-13 gehören genauso gelöscht wie Zeile 6 , die ist mittlerweile auch unnötig .
Danke für den Hinweis ! Hätte die Glatt vergessen zu löschen !

Musste erst einmal verstehen wie der Aufbau ist und wie die head / tail - Steuerung funktioniert um das gelernte um zu setzten .
Deine kleinen Zugaben wie :
Verständnis von static struct hat mir echt noch gefehlt. Mir ist auch einiges über die Wichtigkeit von const aufgefallen . Hatte einige kleinere Denkfehler was die Speicherbelegung und Reservierung angeht .
Was die Sache mit (short/int/long) angeht stimme ich Dir mittlerweile zu. Schwer umzusetzen ! Geht zwar wie man sieht : Macht aber im Grunde mehr Arbeit als Sinn.
 
Zuletzt bearbeitet:

German

Well-Known Member
c-b Experte
#53
Um einen hängended Zeiger (aka Dangling Pointer) für das gelöschte Element zu vermeiden, kannst du auch deine Matrixvariablen aus der main referenzieren und übergeben. Dann hast du die Möglichkeit deren Wert auch NULL zu setzen. Die Deklaration deiner MatrixFree Funktion könnte etwa so aussehen:
int MatrixFree(matrix **const p_matrixptr)
Wenn du den Parameter dereferenzierst, hast du wieder den matrixptr, den du bislang verwendest. Nach Freigabe bringst du noch ein
*p_matrixptr = NULL;
in die Funktion, womit du direkt in den Speicherbereich deiner Variablen in der main schreibst.
BTW So ganz hab ich nicht verstanden warum du die Funktion einen Pointer zurückgeben lässt. Ein int (oder bool, wenn du stdbool.h einbindest) ist doch imo sinnvoller.
 

Eldarius

Well-Known Member
#54
int MatrixFree(matrix **const p_matrixptr)
Wenn du den Parameter dereferenzierst, hast du wieder den matrixptr, den du bislang verwendest. Nach Freigabe bringst du noch ein
*p_matrixptr = NULL;
Nett ! Der "verlorene Zeiger Test" ist zwar nur per Zufall entstanden aber gut zu wissen !

BTW So ganz hab ich nicht verstanden warum du die Funktion einen Pointer zurückgeben lässt. Ein int (oder bool, wenn du stdbool.h einbindest) ist doch imo sinnvoller.
Ja hast du vollkommen recht ein int reicht da völlig ! Außerdem würde der dann auch Wieder Sinn haben ! Die aktuelle Funktion MatrixFree(); liefert zur Zeit immer NULL zurück.

@German
Habe lange Zeit mit deiner For-Schleife verbracht . Musste erst einmal durchsteigen wie du die lns - Adresse ermittelst. Gut als Anfänger kenne ich die normalen Schleifen auch mit mehreren Werten aber das ganze mit Pointern zu sehen ist für mich wie eine Lern - Perle .

Hier aber noch eine Überlegung zur Hauptfrage :
Im Grunde ist unser kleines Programm ja nur ein Lern-Ansatz und im echten Leben überflüssig !
Es ist also sinnvoller gute ,kleine und kompakte Programme in c zu schreiben als zu viel auszulagern und Funktionen dabei übertrieben zu Designen.
Dann ist " C " also eigentlich somit ein Spezialist fürs Grobe ? Nach dem Motto ich brauche mal schnell ne kleine Berechnung oder schaufel den ganzen Tag Daten von a nach b.
Jetzt geht mir aber auch ein Licht auf warum irgendwie alle Sprachen immer noch C-Code zulassen.
 

German

Well-Known Member
c-b Experte
#55
Dann ist " C " also eigentlich somit ein Spezialist fürs Grobe ?
Hehe, das ist dann doch etwas zu stark verallgemeinert. C ist noch relativ maschinennah. (Längst nicht so nah wie Assembler allerdings.) Es ist nur so viel abstrahiert, um auf allen Plattformen mit demselben Umfang von Funktionen zu funktionieren, unabhängig von Prozessoren und Kernelfunktionen. Wobei Plattform-APIs aber auch meist C-like sind und sich direkt einbinden lassen (siehe POSIX oder Windows API). Es existiert also wenig Overhead, was schlanke und schnelle Programme erzeugt. Der Nachteil ist dass man noch viel selbst implementieren muss und dass man viel falsch machen kann, insbesondere was die Speicherverwaltung angeht. Man hat es aber immer unter Kontrolle und kann Speicher freigeben wenn er nicht mehr benötigt wird. Man kann damit also verhindern, dass sich die Arbeitsspeichernutzung von Programmen aufbläht. Höher abstrahierte Sprachen nehmen dir die Speicherverwaltung ab. Das hat den Vorteil, dass du kaum noch Speicherverletzungen erzeugen kannst. Aber, 1.) verleitet es dazu sich keine Gedanken mehr darum zu machen, was da eigentlich in der Implementation abläuft und 2.) entscheiden Garbage Collectors darüber ob und wann Speicher freizugeben ist.
Wie immer gibt es kein schwarz-weiß.
 

Eldarius

Well-Known Member
#56
Auf jeden Fall finde ich das " C " zum Grundwerkzeug gehört und auch noch seine Berechtigung als Sprache hat. War schon keine so schlechte Idee damit anzufangen bevor ich mich mit C++ auseinander setzte .

verleitet es dazu sich keine Gedanken mehr darum zu machen,
Ist ja auch nicht gerade einfach ! Hier wird dann aber schon klar warum so viele junge Leute erst mit anderen Sprachen beginnen.
 

German

Well-Known Member
c-b Experte
#57
Ja, C ist schon nicht schlecht um ein Verständnis dafür zu bekommen, was in anderen Sprachen in der Implementierung verschwindet, aber dennoch passiert. In Bezug auf C++ ist C als Einstieg aber auch nicht ungefährlich. C ist halt immer noch Bestandteil von C++. Nur zu schnell schreibst du einen bunten Mix aus C und C++, verfällst in alte Muster (wie Pointer statt Referenzen zu verwenden oder Speicher selbst zu allozieren), oder schreibst Code prozedural wo eine Klasse vorteilhafter wäre. Wenn es dein Ziel ist, C++ zu lernen, versaut dir C als Einstieg also ggf. den Stil C++ richtig und gut zu schreiben ;)
 

AGGROStar1991

Well-Known Member
c-b Experte
#58
Und es gibt durchaus auch gute Gründe, weder C noch C++ zu wählen wenn man irgendeine Wahl hat für ein Projekt. So sehr man auch von Standards redet. Nichttriviale Projekte sind nicht portabel. Üblicherweise nicht einmal zwischen 2 Compilern auf der selben Plattform oder auch nur zwischen verschiedenen Standardbibliotheken beim selben Compiler. Vom wahnsinnigen Versuch, manche Software einfach mal statisch statt dynamisch zu linken fang ich gar nicht erst an.
Dann kommen die Fehler die es in modernen Sprachen nicht gibt. Undefined Behavior aka "Der Compiler macht im Blindflug was er für richtig hält", Overflows jeglicher Couleur, Formatstring-Vulnerabilities, die ganze Klasse der Pointerfehler als solche, das inexistente oder unbenutzbare Exception-System... Sowas sollte man grundsätzlich nicht vergessen, grad wenn es die erste Sprache ist. Ja man kann es sicherlich mit C/C++ machen. Man kann für die Autoreinigung aber auch eine elektrische Zahnbürste nutzen von der man weiß dass sie mit einer bestimmten Wahrscheinlichkeit explodiert.

so als kleiner Einschub^^
 

Eldarius

Well-Known Member
#59
Da hoffe ich doch das die 6 Monate nicht so ins Gewicht fallen . Ich persönlich interessierte mich schon sehr für C . Der Arbeitsmarkt sagt aber es werden ein Haufen Leute in C++ gesucht .
Ich finde es immer besser den Grundstock zu verstehen und darauf aufzubauen .Es ist halt unbestreitbar das " C " halt die Mutter aller Dinge ist. Wenn mein Kurs beginnt werde ich eh versuchen alles gelernte zu vergessen und neu anfangen. Die Finger von " C " werde ich nach der Fortbildung bestimmt nicht lassen können .
 

AGGROStar1991

Well-Known Member
c-b Experte
#60
Du hast da sehr seltsame Vorstellungen von Didaktik und davon was die Grundlagen sind ;)
Du musst verstehen dass es beim Programmieren so sehr um Programmiersprachen geht, wie in der Astrophysik um große Teleskope. Also wenn du Grundlagen willst wäre es eigentlich eine gute Idee mit anderem Kram anzufangen, Logik oder Algorithmik zum Beispiel.
Didaktisch hat da German nun einmal recht. Selbst auf C++-Kongressen gibt es Vorträge die dann "Stop teaching C!"-heißen und genau dagegen wettern, für C++ zuerst C zu lernen. Wenn du nicht planst C oder C-Libraries zu nutzen bietet es keinen Mehrwert für irgendetwas anderes.

Die Idee C sei "die Mutter aller Dinge" nur weil darin viel Zeug geschrieben ist finde ich grotesk, aber da hab ich jetzt keine Lust einzusteigen. Nur so viel : C ist NICHT!!!! der Grundstock. Man kann jede moderne Programmiersprache als den Versuch deuten, etwas weniger beschissenes zu bauen als C. Wenn es bei den Programmiersprachen Mütter gibt aus dem die Prinzipien entspringen heißen sie Lisp und Smalltalk.

Hab auch nicht vor da groß weiter zu derailen. Aber wenn du C++ lernen willst lern C++ und vergiss alles das du von C weißt möglichst schnell.
 
Oben