# Duplikate nicht aufscheinen lassen - C



## 0664jester (4. Februar 2014)

Hallo,

Ich habe eine CSV Datei mit strtok aufgesplittet.

Vorher:
Person A;Person B
Person A;Person C
Person B;Person A


Nachher:
Person A
Person B
Person A
Person C
Person B
Person A


Nun möchte ich die ganze Liste ausgeben lassen. das Problem ist, dass hier mehrmal Person A stehen hab.
Natürlich möchte ich das nur einmal machen. Wie kann ich das machen mit strcmp oder einen struct anlegen?
Sie sollten auch alphabetisch sein. Es soll in einer Funktion verpackt werden. 

puffer war vorher


```
char *ArraySplitten(char *puffer)
{
  printf("Split array");
  char *token;
  char delimiter1[] = ";";
 // char delimiter2[] = "\n";
  
  token = strtok(puffer, delimiter1);
  
  while(token != NULL)
  {
    printf("%s\n", token);
    token = strtok(NULL, delimiter1);
  }
  return token;
}
```

token ist nachher


lg


----------



## Jennesta (4. Februar 2014)

Hallo,

wenn du die Liste sowieso sortieren willst, dann kannst du das quasi sehr einfach verbinden. Z.B. musst du um die Werte zu vergleichen sowieso mit strcmp arbeiten. Dann kannst du falls die Werte gleich sind einfach für den neuen Wert an dieser Stelle abbrechen.

Dabei hast du quasi zwei Möglichkeiten Liste anlegen, alle hinzufügen und mit sort und unique arbeiten, oder schon beim einsortieren aussortieren. Kommt hier quasi auf Bequemlichkeit und Laufzeitrelevanz an.

Grüße Jennesta


----------



## 0664jester (5. Februar 2014)

ich probier mal die erste Möglichkeit(alle hinzufügen) - denk mal ich kann die liste vllt noch für andere funktionen gebrauchen...


Meinst du mit sort "quicksort" oder qsort? 

Ist unique auch schon was vorgefertigtes von der stdlib.h?

lg


----------



## Jennesta (5. Februar 2014)

Hallo,

das sind beides Funktionen der Klasse list aus der STL.
Hier mal den Link zu unique

Grüße


----------



## Cromon (5. Februar 2014)

0664jester hat gesagt.:


> ich probier mal die erste Möglichkeit(alle hinzufügen) - denk mal ich kann die liste vllt noch für andere funktionen gebrauchen...
> 
> 
> Meinst du mit sort "quicksort" oder qsort?
> ...



std::sort, std::unique -> C++
qsort -> C


----------



## 0664jester (5. Februar 2014)

hilft mir leider nix da ich in c schreibe. sry, dass ich das nicht ganz am anfang hingeschrieben habe...


----------



## Cromon (5. Februar 2014)

In C kannst du qsort zum sortieren verwenden. Die Verwendung ist relativ simpel. Bei Problemen einfach posten.


----------



## 0664jester (5. Februar 2014)

ja, bitte um hilfe. Ich verstehe den qsort nicht ganz:

einfach .txt mit .c ersetzen:
http://www.tutorials.de/attachment.php?attachmentid=63003&stc=1&d=1391625047


ab zeile 60...

Den qsort kann man ja nicht in eine eigen funktion schreiben, oder? 
Deswegen habe ich ihn in die main gegeben...


lg


----------



## sheel (5. Februar 2014)

Was verstehst du nicht?
Und warum soll man qsort nicht in Funktionen verwenden können?


----------



## 0664jester (5. Februar 2014)

Zeile 66:

```
qsort(token,3,sizeof(*token),(int(*)(const void*,const void*))strcmp);
```

Einerseits schaffe ich nicht den 3er zuersetzen mit etwas sinnvollen,was die Anzahl der Einträge von token abzählt...
andererseits verstehe ich diesen teil nich (int(*)(const void*,const void*))strcmp) was der überhaupt aussagt.


Das Problem ist, dass ich in eine Endlosschleife komme... ansonsten spuckt das Programm ja was aus...


----------



## Jennesta (5. Februar 2014)

Hallo,
(int(*)(const void*,const void*))strcmp) soll im Grunde heißen, dass du der qsort-Funktion als Argument eine Funktion mit Rückgabewert int, sowie zwei Parametern des Typs void* übergibst.

Die qsort-Funktion nutzt diese Funktion um deine Werte zu sortieren, da sie gegebenenfalls nicht weiß, wie sie bei eigenen Typen zu verfahren hat. Als simples Beispiel schaue mal über folgenden Code. Du castest die Parameter einfach zu den Typen, die du vergleichen willst (in deinem Falle (char*)) und vergleichst dann. Z.B. mit strcmp.


```
int compareMyType (const void * a, const void * b)
{
  if ( *(MyType*)a <  *(MyType*)b ) return -1;
  if ( *(MyType*)a == *(MyType*)b ) return 0;
  if ( *(MyType*)a >  *(MyType*)b ) return 1;
}
```

Die qsort-Funktion erwartet als ersten Parameter übrigens die Basis deines Arrays. Wenn ich das richtig verstehe, was du gemacht hast, dann ist token aber kein Array. Schau dir nochmal hier das Beispiel der qsort-Funktion an

Grüße,
Jennesta


----------



## 0664jester (6. Februar 2014)

strtok macht eigentlich einen pointer


hab aber das eigentlich problem gefunden:
Die folgende funktion wirft ganz am Ende ein <NULL> pointer raus. 


```
char *ArraySplitten(char *puffer)
{
  printf("Split array");
  char *token;
  char delimiter1[] = ";";
  char delimiter2[] = "\0";
  
  token = strtok(puffer, delimiter1);
  
  while(token != NULL)
  {
    printf("%s\n", token);
    token = strtok(NULL, delimiter1);
  }
   
  return token;
}
```

Wie kann ich in der Funktion, mein einträge in einer verkette liste speichern?


----------



## sheel (6. Februar 2014)

Ja und? qsort will ein Array von Daten.


----------



## 0664jester (6. Februar 2014)

null ist weg


----------



## sheel (6. Februar 2014)

Versteh ich nicht.
Wenn du nicht verstehst, was ein Array ist, bitte nachlesen
http://openbook.galileocomputing.de/c_von_a_bis_z/
usw

gerade erst das edit oben gesehen:
Warum eine verkettete Liste?
...
qsort funktioniert wirklich wirklich nur mit Arrays.


----------



## 0664jester (6. Februar 2014)

zuerst will ich alle personen auflisten lassen, ohne dass sie doppelt vorkommen... deswegen die funktion array splitten...

bei Person A;Person B, bedeutet der ";" dass sie sich kennen also befreundet sind. 
Also habe ich mir gedacht über einen struct die Beziehungen zwischen den Personen herstellen...


----------



## Jennesta (6. Februar 2014)

0664jester hat gesagt.:


> bei Person A;Person B, bedeutet der ";" dass sie sich kennen also befreundet sind.
> Also habe ich mir gedacht über einen struct die Beziehungen zwischen den Personen herstellen...



Wenn wir dir helfen sollen, dann müsstest du auch einmal auf unsere Antworten eingehen. Ich habe das Gefühl, dass jeden Beitrag von dir ein neues Problem hinzukommt. Ich weiß inzwishcen gar nicht mehr was du hast und was noch nicht funktioniert.


----------



## 0664jester (12. Februar 2014)

@jennesta: ja, da hast du recht. wenn ich wo hänge, arbeite ich meistens wo anders weiter bis mir etwas einfällt... 


um die Personen zu teilen habe ich es nun mit pointern gemacht... (strchr(csvline, ';') gibt mir einen pointer zurück wo der liegt) dann prüfe ich ob ; nicht als erstes oder letztes vorkommt.
ersetze ; mit \0 und lasse einen pointer auf den anfang zeigen und einen nach \0 zeigen so kann ich beide streams einlesen...


----------



## 0664jester (13. Februar 2014)

Bei mein programm kommt immer in der addFront funktion zum absturz. 
Kann mir jemand helfen und sagen was falsch ist? 

ich bekomme keine fehlermeldungen...



```
typedef struct llnode
{
  char *name;
  struct llnode *next;
 // struct node *prev;  
} llnode;
  
struct llnode *head = NULL;  //initialiere den head


void addFront(char *prasemi /*, char *postsemi*/)
{
  struct llnode *tempnode1;
 // struct llnode *tempnode2;
  tempnode1 = (struct llnode*)malloc(sizeof(struct llnode));
//  tempnode2 = (struct llnode*)malloc(sizeof(struct llnode));
  strcpy(tempnode1 -> name, prasemi);
//  strcpy(tempnode2 -> name, postsemi);
  
  
  if(head == NULL) 
  {
    head = tempnode1;
    head -> next = NULL;
  }
  else
  {
    tempnode1 -> next = head;
    head = tempnode1;
  }
  
}
```


----------



## Cromon (13. Februar 2014)

Hallo 0664jester


```
strcpy(tempnode1 -> name, prasemi);
```

Für name ist kein Speicher alloziert, du kopierst hier also den String irgendwo ins Nirvana.

Viele Grüsse
Cromon


----------



## 0664jester (13. Februar 2014)

danke.

ich hab den char pointer  eine fixe länge gegeben:
  char name[100];


----------



## 0664jester (16. Februar 2014)

```
typedef struct llnode
{
  char *name;
  struct llnode *next;
 // struct node *prev;  
} llnode;
  
struct llnode *head = NULL;  //initialiere den head
 
 
void addFront(char *prasemi)
{
  struct llnode *tempnode1;
  tempnode1 = (struct llnode*)malloc(sizeof(struct llnode));
  strcpy(tempnode1 -> name, prasemi);

  
  
  if(head == NULL) 
  {
    head = tempnode1;
    head -> next = NULL;
  }
  else
 {
    while(memcmp(head, tempnode1, sizeof(&tempnode1) < 0 ))
    {
      head = tempnode1 -> next;
      if(memcmp(head, head -> next, sizeof(&tempnode1)) > 0 )
      {
        head = tempnode1 -> next;
      }
    }
  }
  
}
```

nach dem else in der while schleife habe ich irgendeinen wurm drinnen...
Kann mich jemand auf die sprünge helfen?


----------



## Cromon (16. Februar 2014)

Hallo 0664jester

Das hier ist weiter nicht legal:

```
tempnode1 = (struct llnode*)malloc(sizeof(struct llnode));
  strcpy(tempnode1 -> name, prasemi);
```

String wird ins Nirvana kopiert. Verwende strdup und anschliessed free oder mache den Member name von einer statischen Grösse und stelle bei strcpy sicher, dass nicht mehr kopiert wird.

Was deine while-Schleife machen soll verstehe ich überhaupt nicht. Du vergleichst den Speicher des neu allozierten Nodes mit head, was bringt das? Das wird unter diesen Bedingungen immer verschieden sein, da next bei tempnode1 einen random (inkorrekten) Wert hat und name hat auch einen zufälligen inkorrekten Wert.

Innerhalb der Schleife verwendest du tempnode1->next für Head. Dies macht überhaupt keinen Sinn, next hat einen komplett zufälligen Wert, da du ja deinen allozierten Speicher nicht initialisierst, das dürfte also bereits im Ersten Schleifendurchgang einen Crash ergeben.

Was du (so vermute ich) machen willst ist folgendes:

```
struct llnode* tempnode1, *itr;
tempnode1 = (struct llnode*) malloc(sizeof(struct llnode));
tempnode1->name = strdup(prasemi);
tempnode1->next = NULL;

if(head == NULL) {
    head = tempnode1;
} else {
    itr = head;

    while(itr->next != NULL) {
        itr = itr->next;
    }

    itr->next = tempnode1;
}
```

Grüsse
Cromon


----------



## 0664jester (16. Februar 2014)

danke für die hilfe


```
void anHaengen(char *prasemi)
{
  llnode *zeiger; //Zeiger für den Zugriff auf einzelne Elmente
  
  if(head == NULL) //gibt es schon ein Element in der Liste?
  {
     if((head = malloc(sizeof(struct llnode))) == NULL) 
     {
       printf("Kein Speicherplatz vorhanden fuer anfang\n");
       return;
     }
   strcpy(head->name, strdup(prasemi));  //Wenn nein
   head->next = NULL; 
  }
  else
  {
    zeiger = head;
    while(zeiger->next != NULL)
    {
      zeiger = zeiger->next;
      if((zeiger->next = malloc(sizeof(struct llnode))) == NULL) 
      {
        printf("Kein Speicherplatz für das letzte Element\n");
        return;
      }
      zeiger=zeiger->next;
      strcpy(zeiger->name,strdup(prasemi));
      zeiger->next=NULL;
    }
  }
}
//------------------------------------------------------------------------------
 
void sortList(char *prasemi)
{
    llnode *zeiger;
    llnode *zeiger1;
    
    if(head == NULL) //ist es das erste Element in der Liste?
    {
      anHaengen(prasemi);
    }
    else // Suche solange bis es gefunden wird
    {
      zeiger = head;
      while(zeiger != NULL && (strcmp(zeiger->name, strdup(prasemi))<0)) //abdef
      {
        zeiger = zeiger->next; //zeiger ist geht bis  vor d
      }
      if(zeiger == NULL) // wenn null ist dann hinten anhängen
      {
        anHaengen(prasemi);
      }
      else if(zeiger == head) //unser Elment das kleinste ist - vor head einfügen
      {
        zeiger = malloc(sizeof(struct llnode));
        if(NULL == head)
        {
          printf("Kein Speicher\n");
          return;
        }
        strcpy(head->name,strdup(prasemi));
        head->next=zeiger;
      }
      else //Element ist irgendwo in der Mitte
      {
        zeiger1 = head;
        while(zeiger1->next != zeiger)//suchen das Element das nicht vor Zeiger steht
        {
          zeiger1=zeiger1->next;
        }
        zeiger = malloc(sizeof(struct llnode));
        if(NULL==zeiger)
        {
          printf("Kein Speicher\n");
          return;
        }
      strcpy(zeiger->name,strdup(prasemi));
      zeiger->next = zeiger1->next;
      zeiger1->next = zeiger;
      }
  }
}

//------------------------------------------------------------------------------ 
void printList()
{
    struct llnode *currentnode;
    currentnode = head;
 
    while(currentnode != NULL)
    {
        printf("%s\n", currentnode->name);
        currentnode = currentnode->next;
    }
}
```

Output:
Amber Sally Hopkins
Grady Miller
Julian Reynolds
Roy Floyd
Tamara Robertson
CD6

Leider fehlt Kenneth Schneider und das CD6 sollte auch nicht sein...


----------



## Cromon (16. Februar 2014)

Hallo 0664jester


```
strcpy(head->name, strdup(prasemi));  //Wenn nein
```

Weitherin hat der neu allozierte Node kein Speicherplatz in name (ausser Name hat eine statische Grösse). Zudem hast du ein Speicherleck, der Zeiger, der von strdup zurückgegeben wird muss wieder freigegeben werden mit free.


```
while(zeiger->next != NULL)
    {
      zeiger = zeiger->next;
      if((zeiger->next = malloc(sizeof(struct llnode))) == NULL)
```

Du hängst hier an jedes Element deinen Node an und erzeugst damit Speicherlecks und eine komplett falsche Liste.

Viele Grüsse
Cromon


----------



## 0664jester (16. Februar 2014)

char name[100]; sieht so aus bei mir

llnode habe ich so abgehändert...

```
if((head = (struct llnode*) malloc(sizeof(struct llnode))) == NULL) 
     {
       printf("Kein Speicherplatz vorhanden fuer anfang\n");
       return;
```


ich werde nochmal überprüfuen, wenn die liste leer, ob dort ein fehler eingeschlichen hat, weil da der erste nahme fehlt...


----------



## Cromon (16. Februar 2014)

Hallo 0664jester

Wie gesagt, der von dir gepostete Code weiter oben macht etwas ganz anderes als du möchtest. 

Viele Grüsse
Cromon


----------

