Macht das sinnig ?

lano

Well-Known Member
c-b Experte
#1
Moin.

Ich frag mal so direkt.
Gibt das hier was was ich generell am code ueberdenken sollte ?
Makefile:
all:
    gcc main.c universum.c galaxie.c -o start.elf
C:
/* main */
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

#include "universum.h"


int main() {
    int command = 0;
    int data;
    
    Universum* Univers = NULL;
    Universum* tmp = NULL;
    callbackUniversum disp = ShowUniversum;
    
    MainMenu();
    while(1) {
        printf("\nEnter a command(0-10,-1 to quit):");
        scanf("%d",&command);
        
        if(command == -1)
            break;
        switch(command) {
            case 0:
                MainMenu();
                break;
             case 1:
                printf("Wie viele Universen sollen erstellt werden ? ");
                scanf("%d",&data);
                Univers = GenerateNewUniversum(Univers,data);
                //traverse(Univers,disp);
                break;
            case 2:
                    if(Univers != NULL) {
                        ShowAllUniversum(Univers,disp);
                } else {
                    printf("Universum not found.\n");
                }
                break;
        }
        
    }
    DestroyUniversum(Univers);
    return 0;
}
 

lano

Well-Known Member
c-b Experte
#2
C:
#ifndef HEADER_universum
#define HEADER_universum

#include "galaxie.h"

typedef struct Universum {
    char namen[100];
    int radius;
    struct Galaxie Galaxie;
    int data;
    struct Universum* next;
} Universum;

typedef void (*callbackUniversum)(Universum* data);


Universum* GenerateNewUniversum(Universum* head, int anzahl);

/* Neues Universum erstellen */
Universum* CreateNewUniversum(char *namen,int radius,int galaxien,int data,Universum* next);
 


void ShowUniversum(Universum* n);
void ShowAllUniversum(Universum* head,callbackUniversum f);


void MainMenu(void);

  


void DestroyUniversum(Universum *head);

#endif
C:
/* universum */
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>

#include "universum.h"
#include "galaxie.h"

/* Generiere x Universen */
Universum * GenerateNewUniversum(Universum* head, int anzahl) {
    
    srand(time(NULL));
    
    /* Namen zufaellig aus einer Datei waehlen */
    char namen[100] = "Hallo";
    /* Radius zufaellig waehlen zwischen x und y, was son universum halt so gros ist */
    int radius = 0;
    /* Anzahl der Galaxien nen bisschen von der groesse abhaengig machen */
    int galaxien = 0;
    /* Nur zum Test */
    int data = 0;
    
    for (int i = 0; i < anzahl; i++) {
        data = rand() % 1000;
        radius = rand() % 1000;
        galaxien = rand() % 1000;
        
        printf("New Universum #%d generated.\n",i+1);
        Universum* new_node = CreateNewUniversum(namen,radius,galaxien,data,head);
        head = new_node;
    }
    return head;
}


/*
 *   Add a new Universum
 */
Universum* CreateNewUniversum(char *namen,int radius,int galaxien,int data,Universum* next) {
    Universum* new_node = (Universum*)malloc(sizeof(Universum));
    if(new_node == NULL) {
        printf("Error creating a new node.\n");
        exit(0);
    }
    strcpy(new_node->namen, namen);
    new_node->radius = radius;
    new_node->Galaxie = *GenerateNewGalaxie(NULL,2);
    new_node->data = data;
    
    new_node->data = data;
    new_node->next = next;
    
return new_node;
}


/*
 *   traverse the univers list
 */
void ShowAllUniversum(Universum* head,callbackUniversum f) {
    Universum* cursor = head;
    while(cursor != NULL) {
        f(cursor);
        cursor = cursor->next;
    }
}

/*
 *   Zeige ein Universum
 */
void ShowUniversum(Universum* n) {

    callbackGalaxie disp = ShowGalaxie;
    
    
    if(n != NULL) {
        printf("Name: %s \n", n->namen);
        printf("Radius: %d \n", n->radius);
        ShowAllGalaxie(&n->Galaxie,disp);
        printf("Data: %d \n\n", n->data);
    }
}


/*
 *   remove all element of the univers list
 */
void DestroyUniversum(Universum *head) {
    Universum *cursor, *tmp;
    
    if(head != NULL) {
        cursor = head->next;
        head->next = NULL;
        while(cursor != NULL) {
            tmp = cursor->next;
            free(cursor);
            cursor = tmp;
        }
    }
}

/*
 *   display the menu
 */
void MainMenu(void) {
    printf("--- lano's Universum --- \n\n");
    printf("0.Menu anzeigen\n");
    printf("1.Neues Universum generieren\n");
    printf("2.Alle Universen anzeigen\n");
    printf("-1.quit\n");
    
}
 

lano

Well-Known Member
c-b Experte
#3
C:
#ifndef HEADER_galaxie
#define HEADER_galaxie


typedef struct Galaxie {
    char namen[100];
    int radius;
    int galaxien;
    int data;
    struct Galaxie* next;
} Galaxie;

typedef void (*callbackGalaxie)(Galaxie* data);


Galaxie* GenerateNewGalaxie(Galaxie* head, int anzahl);

/* Neue Galaxie erstellen */
Galaxie* CreateNewGalaxie(char *namen,int radius,int galaxien,int data,Galaxie* next);

void ShowGalaxie(Galaxie* n);
void ShowAllGalaxie(Galaxie* head,callbackGalaxie f);
void MainMenuGalaxie(void);

void DestroyGalaxie(Galaxie *head);

#endif
C:
/* galaxie */
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>

#include "galaxie.h"


Galaxie * GenerateNewGalaxie(Galaxie* head, int anzahl) {
    
    srand(time(NULL));
    
    char namen[100] = "Hallo";
    int radius = 0;
    int galaxien = 0;
    int data = 0;
    
    for (int i = 0; i < anzahl; i++) {
        data = rand() % 1000;
        radius = rand() % 1000;
        galaxien = rand() % 1000;
        
        printf("New Galaxie #%d generated.\n",i+1);
        Galaxie* new_node = CreateNewGalaxie(namen,radius,galaxien,data,head);
        head = new_node;
    }
    return head;
}



Galaxie* CreateNewGalaxie(char *namen,int radius,int galaxien,int data,Galaxie* next) {
    Galaxie* new_node = (Galaxie*)malloc(sizeof(Galaxie));
    if(new_node == NULL) {
        printf("Error creating a new node.\n");
        exit(0);
    }
    strcpy(new_node->namen, namen);
    new_node->radius = radius;
    new_node->galaxien = galaxien;
    new_node->data = data;
    
    new_node->data = data;
    new_node->next = next;
    
    return new_node;
}


void ShowAllGalaxie(Galaxie* head,callbackGalaxie f) {
    Galaxie* cursor = head;
    while(cursor != NULL) {
        f(cursor);
        cursor = cursor->next;
    }
}


void ShowGalaxie(Galaxie* n) {
    if(n != NULL) {
        printf("Name: %s \n", n->namen);
        printf("Radius: %d \n", n->radius);
        printf("Galaxien: %d \n", n->galaxien);
        printf("Data: %d \n\n", n->data);
    }
}



void DestroyGalaxie(Galaxie *head) {
    Galaxie *cursor, *tmp;
    
    if(head != NULL) {
        cursor = head->next;
        head->next = NULL;
        while(cursor != NULL) {
            tmp = cursor->next;
            free(cursor);
            cursor = tmp;
        }
    }
}
 

German

Well-Known Member
c-b Experte
#4
C:
typedef struct Universum {
    char namen[100];
    int radius;
    struct Galaxie Galaxie;
    int data;
    struct Universum* next;
} Universum;
struct Galaxie Galaxie; sieht komisch aus. Galaxie *Galaxien; rein intuitiv. Immerhin könnte dein Universum ja auch keine Galaxie enthalten. Also NULL Pointer.
 

German

Well-Known Member
c-b Experte
#5
Idee:
Ein Objekt hat
- private Daten/Eigenschaften (Typ, Name, Radius)
- Kinder (ein Universum hat Galaxien, oder eine Galaxie hat Sonnensysteme)
- Geschwister (Paralleluniversen, Nachbargalaxien in einem Universum, …)
C:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

#define STRING_SIZE 512

typedef enum {nothing, universe, galaxy, solar_system} object_t;

struct object
{
  void *data;
  struct object *first_child;
  struct object *next_sibling;
};

struct object_data
{
  object_t type;
  char name[STRING_SIZE];
  int radius;
};


struct object_data *InitObjectData(const object_t type, const char *const name, const int radius)
{
  struct object_data *new_data = calloc(1u, sizeof(struct object_data));
  if (new_data == NULL)
    return NULL;

  new_data->type = type;
  strncpy(new_data->name, name, STRING_SIZE - 1);
  new_data->radius = radius;
  return new_data;
}


struct object *PushBack(struct object **const p_head, void *const data)
{
  struct object *head = *p_head;
  struct object *new_object = calloc(1u, sizeof(struct object));
  if (new_object == NULL)
    return false;

  new_object->data = data;
  if (head == NULL)
    *p_head = new_object;
  else
  {
    for ( ;head->next_sibling != NULL; head = head->next_sibling);
    head->next_sibling = new_object;
  }

  return new_object;
}


struct object *GetPointerOfIndex(struct object *head, const unsigned index)
{
  for (unsigned i = 0u; i < index; ++i)
  {
    if (head == NULL)
      return NULL;

    head = head->next_sibling;
  }

  return head;
}


void Destroy(struct object **const p_head)
{
  if (*p_head != NULL)
  {
    free((*p_head)->data);

    if ((*p_head)->first_child != NULL)
      Destroy(&(*p_head)->first_child);

    if ((*p_head)->next_sibling != NULL)
      Destroy(&(*p_head)->next_sibling);

    free(*p_head);
    *p_head = NULL;
  }
}


void PrintTree(const struct object *head, const unsigned indent)
{
  static const char *const types[] = {"nothing", "universe", "galaxy", "solar system"};
  if (head == NULL)
    return;

  char *indentation = calloc(indent + 1u, 1u);
  if (indentation == NULL)
    return;

  for (unsigned i = 0u; i < indent; ++i)
    indentation[i] = ' ';

  printf("\n%sData:\n", indentation);
  if (head->data != NULL)
  {
    printf("%s Type: %s\n"
           "%s Name: %s\n"
           "%s Radius: %d\n",
           indentation, types[((struct object_data*)head->data)->type],
           indentation, ((struct object_data*)head->data)->name,
           indentation, ((struct object_data*)head->data)->radius);
  }

  free(indentation);

  if (head->first_child != NULL)
    PrintTree(head->first_child, indent + 4u);

  if (head->next_sibling != NULL)
    PrintTree(head->next_sibling, indent);
}

int main(void)
{
  struct object *universes = NULL,
                *current_universe = NULL,
                *current_galaxy = NULL;
  struct object_data *data = NULL;

  if (
    (data = InitObjectData(universe, "U1", 10000000)) == NULL
    || PushBack(&universes, data) == NULL
    || (data = InitObjectData(galaxy, "G1", 500)) == NULL
    || PushBack(&universes->first_child, data) == NULL
    || (data = InitObjectData(galaxy, "G2", 200)) == NULL
    || (current_galaxy = PushBack(&universes->first_child, data)) == NULL
    || (data = InitObjectData(solar_system, "S1", 5)) == NULL
    || PushBack(&current_galaxy->first_child, data) == NULL
    || (data = InitObjectData(universe, "U2", 20000000)) == NULL
    || (current_universe = PushBack(&universes, data)) == NULL
    || (data = InitObjectData(galaxy, "G3", 300)) == NULL
    || PushBack(&current_universe->first_child, data) == NULL
  )
  {
    Destroy(&universes);
    return 1;
  }

  PrintTree(universes, 0);
  Destroy(&universes);

  return 0;
}
Beispielausgabe:
Code:
Data:
 Type: universe
 Name: U1
 Radius: 10000000

    Data:
     Type: galaxy
     Name: G1
     Radius: 500

    Data:
     Type: galaxy
     Name: G2
     Radius: 200

        Data:
         Type: solar system
         Name: S1
         Radius: 5

Data:
 Type: universe
 Name: U2
 Radius: 20000000

    Data:
     Type: galaxy
     Name: G3
     Radius: 300
Die privaten Daten haben jetzt bei mir alle den object_data Typ. Natürlich kannst du unterschiedliche Strukturen für unterschiedliche Objekte anlegen, sofern es andere Attribute für unterschiedliche Objekte gibt. Der Typ sollte dann immer das erste Member sein. Das ist der Grund warum die object Struktur an der Stelle einen void* vorsieht. Wenn du den zum int* castest kannst du den Typ lesen. Anschließend in Abhängigkeit vom Typ zum entsprechenden Pointer der passenden Struktur. Kann ich dir aber auch noch mal vorturnen, wenn gewünscht.
 

lano

Well-Known Member
c-b Experte
#6
Ja ok, nen n ...

Ein Objekt hat
- private Daten/Eigenschaften (Typ, Name, Radius)
- Kinder (ein Universum hat Galaxien, oder eine Galaxie hat Sonnensysteme)
- Geschwister (Paralleluniversen, Nachbargalaxien in einem Universum, …)
Das sind schon unterschiedliche objekte. Ich hab mir halt gedacht das ich das so immer weiter aufdroesel. Bis zur muenze :)

Aber wo wir schon grad dabei sind. den namen zb. Ich koennte kghikuh generieren. Aber ich hab mir das so gedacht.
Ich hab Textdateien mit Namen, Vornamen, Nachnamen, Strassennamen, usw ...
Ware doch doof wenn ich da jetzt immer kopieren wuerde. Da doch lieber mmap und nen pointer ?
 

German

Well-Known Member
c-b Experte
#7
Das sind schon unterschiedliche objekte. Ich hab mir halt gedacht das ich das so immer weiter aufdroesel. Bis zur muenze :)
Ja, warum nicht? Hab ja geschrieben, an den data Pointer kannst du anhängen was du willst ;) Du sparst dir endlos Code. Wenn du für jede Linked List eigene Routinen schreiben willst, kannst du dir vorstellen, was daraus wird wenn du das bis zur Münze runterbrichst.
Er, what?
Ware doch doof wenn ich da jetzt immer kopieren wuerde. Da doch lieber mmap und nen pointer ?
Das ist wieder so ein POSIX Dingens. Wie konsistent wird das denn und wie stark leidet die Performance wenn du ständig auf dem Dateisystem rumliest? Klar, das Kopieren frisst beim Anlegen des Baums einiges an Ressourcen, aber dann arbeitest du im Arbeitsspeicher.
 

asc

Well-Known Member
c-b Experte
#8
Ware doch doof wenn ich da jetzt immer kopieren wuerde. Da doch lieber mmap und nen pointer ?
Da limitierst du dich aber auf eine bestimmte Länge der Namen, da du ja irgendwie ein fixes Offset brauchst, oder wie hast du dir das gedacht?
Oder willst du eine Binäre Datei laden und auf Null-Byte Suche gehen?

Davon abgesehen würde ich trotzdem Kopieren und nicht auf den gemappten Speicher zeigen ;)
Warum? Weil ich es nicht so geil finden würde, wenn der Speicher später (ggf. durch einen Programmfehler) un-gemappt wird und auf einmal alle Zeiger in den Datenstrukturen invalid werden. Klar ist unwahrscheinlich, aber eben vermeidbar.

Achja, und wenn man die Namen in den Objekten ggf. mal ändern will (z.b. Umbenennen/einen eigenen Namen festlegen) ginge das mit Kopien ziemlich einfach.

Vielleicht wäre es einfacher, die Namen aus der Datei selbst zu parsen und in einer Liste/Vektor zu speichern die du dann nutzen kannst um zufällig einen Namen zu picken.
 

lano

Well-Known Member
c-b Experte
#9
Klar, das Kopieren frisst beim Anlegen des Baums einiges an Ressourcen, aber dann arbeitest du im Arbeitsspeicher.
Und der ist begrenzt. Von daher dachte ich ich speichere da lieber ne nummer als nen langen string.

oder wie hast du dir das gedacht?
gedacht ? ... nicht wirklich.

Oder willst du eine Binäre Datei laden und auf Null-Byte Suche gehen?
Newline?

Vielleicht wäre es einfacher, die Namen aus der Datei selbst zu parsen und in einer Liste/Vektor zu speichern die du dann nutzen kannst um zufällig einen Namen zu picken.
Das doch aber auch irgendwie langweilig. Ich werds jetzt erstmal so machen.
 

German

Well-Known Member
c-b Experte
#10
Von daher dachte ich ich speichere da lieber ne nummer als nen langen string.
Ja, ne Adresse speichern ist schon weniger speicherintensiv. Aber der Aufwand an die Adresse zu kommen ist derselbe. Macht es dann nicht mehr Sinn den Inhalt nur dann zu suchen und nachzuladen wenn er wirklich gebraucht wird? Aus 'ner Datenbank die für sowas optimiert ist, versteht sich. Textdatei mappen ist schon irgendwie merkwürdig.
Ja, so etwa wäre auch meine Vorstellung gewesen. Muss nicht nullterminiert sein. Einfach den Pointer auf das erste Zeichen so lange inkrementieren und zeichenweise ausgeben, bis ein oder einer von mehreren festgelegten Delimiters gefunden wird. strpbrk() könnte da Vorarbeit leisten, bedeutet aber dass du zweimal über den Teilstring rennst - einmal zum Suchen und einmal für die Ausgabe.
 
Oben