Aus einem String alle Leerzeichen entfernen

free() bedeutet den Speicher wieder freigeben, den du mit malloc() alloziert hast. runner zeigt ja auf gar keinen reservierten Speicher, hier darfst du kein free() anwenden. temp zeigt auf reservierten Speicher, da gehört das free() hin.

Lg
 
Ok, ja ich hab das etwas zu eilig gepostet^^
Code:
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>

char *eraseAllBlanks(char *str){
    char *runner=str;
    char *temp=(char *)malloc(strlen(str));

    while (*runner!='\0'){
           while(*runner==' ')
               runner++;
           temp=runner;
           temp++;
           runner++;
    }
    runner=temp;
    free(temp);
    return runner;
}

void main (void){
    char *in="Ha llo W e lt   ";
    printf("%s", eraseAllBlanks(in));
}
Das Programm gibt nichts aus. Anscheinend läuft beim Ablaufen was schief (vermutlich irgendwelche Zuordnungen)
 
Zuletzt bearbeitet:
Also, lassen wir das mal rekapitulieren:

- In der Funktion eraseAllBlanks erstellst du einen Character-Pointer, der auf den Speicher wir str zeigt.
- Dann wird ein Character-Pointer temp erzeugt und speicher in Größe von Länge(str) angefordertert - hier wird schon mal nicht auf NULL geprüft, was fahrlässig ist, aber gut, es funktioniert zu mindest.
- Anschließend kommt die Schleife, die über alle Zeichen in runner (und damit auch in str) prüft.
- Innerhalb der Schleife wird noch mal eine Schleife geloopt, in der alle Leerzeichen ignoriert werden.
- Anschließend wird der Pointer von runner an den Pointer von temp geschrieben
- Jetzt wird der temp- und der runner-Pointer um eins erhöht.

Soweit ist das alles in Ordnung, aber jetzt kommt der Denkfehler:
- Nach der Schleife wird der aktuelle Pointer von runner mit dem Pointer von temp überschrieben.
- Jetzt wird temp aus dem Speicher entlassen, temp zeigt jetzt irgendwo hin nur nicht mehr an den Anfang, wo der original angeforderte Speicher ursprünglich mal adressiert wurde - hier hast zu zu mindest mal ein Memory-Leak
- Dann wird der aktuelle Zeiger von runner zurück gegeben - runner zeigt aber auch nicht mehr auf den Anfang, sondern sehr wahrscheinlich auf das Ende des Strings, eine \0.

Damit ist klar, warum nichts ausgegeben wird.
 
Ok, ich habe dann gedacht man könnte einen Pointer auf die erste Position des Strings setzen, was aber eine if-Bedingung (zum Abfangen des ersten Buchstabens) vor der while-Schleife bedeuten würde:

Code:
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>

char *eraseAllBlanks(char *str){
    char *runner=str,*start;
    char *temp=(char *)malloc(sizeof(str));

    if(*runner!='\0'){
           while(*runner==' ')
               runner++;
    temp=runner++;
    start=temp++;
    }

    while (*runner!='\0'){
           while(*runner==' ')
               runner++;
           temp=runner++;
           temp++;
    }

    free(temp);
    return start;
}

void main (void){
    char *in="Ha      llo   W e lt   ";
    printf("%s", eraseAllBlanks(in));
}
Funktioniert leider nicht, es wird der komplette String zurückgegeben.
Alternativ könnte ich auch einen Zähler einbauen, den ich dann zurücklaufe?
 
Probiers besser mal so:

Übergib als erstes Mal den String als const char* an die Funktion, so verhinderst du, dass du da was am konstanten String herumarbeitest.
Du erstellst in der Funktion einen Pointer, der auf auf freien Speicher in der Größe des übergebenen Strings zeigt und kopierst dann einfach alles, was kein Leerzeichen ist, in den freien Speicher. Du brauchst nur den übergebenen Pointer und noch einen für den neuen String. Den reservierten Speicher kannst du dann jedoch erst wieder im main() freigeben, in der Funktion darfst du das nicht.

2. Möglichkeit wäre, die Funktion einfach so zu schreiben, dass sie den String bekommt, und noch einen weiteren Pointer auf freien Speicher. Den freien Speicher beschreibst du dann in der Funktion. Dann bräuchtest du auch keinen String zurückgeben, der würde dann ja schon im übergebenen Pointer stehen.

Lg
 
Was spricht denn dagegen, den allokierten Speicher an der Stelle frei zu geben, wo die Funktion eraseAllBlanks aufgerufen wird?

Außerdem ist der Vorschlag von ibafluss gar nicht so schlecht.

Ich würde es allerdings so machen:

C:
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
 
char *eraseAllBlanks(const char *str)
{
  char *buf = malloc(strlen(str));
  if( buf == NULL )
    return NULL;

  while(*str)
  {
    if( *str != ' ' )
     *buf++ = *str;
    str++;
  }

  return buf;
}

int main (int argc, char **argv)
{
  char *in="Ha      llo   W e lt   ";
  char *out = eraseAllBlanks(in);

  printf("%s", out);

  free(out);
}
 
Naja ein free() außerhalb der Funktion wirkt insofern komisch, dass ich mit dem erzeugten String weiterarbeiten will und es vielleicht nicht ersichtlich ist, dass an anderer Stelle Speicherplatz für den String alloziert wurde.
Das Ganze würde nacher folgendermaßen aussehen
1. Lies Zeile aus Datei in String
2. Entferne alle Leerzeichen aus dem String
3. Werte String aus (eigentliche Operation)
4. Speicherplatz wieder freigeben

Deshalb würden zwei Übergabeparameter die Sache eher unübersichtlicher machen, da das Entfernen der Leerzeichen eine Nebenoperation ist.

@saftmeister Dein Quelltext funktioniert leider auch nicht. Es wird immer ausgegeben "ata/Local", also ein Teil eines Pfades. Was ich mich auch frage ist, ob die Bedingung der Schleife
Code:
 while(*str)
wirklich beim Stringende greift?!
 
Sorry, hab nicht getestet. Ich hab die gleichen Fehler reingebaut, wie bei dir...

Hier die überarbeitete funktionierende Version:

C:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
char *eraseAllBlanks(const char *str)
{
  char *dst, *src;
  char *buf = malloc(strlen(str));
  if( buf == NULL )
    return NULL;

  memset(buf, 0, strlen(str));
 
  src = str;
  dst = buf;

  while(*src)
  {
    if( *src != ' ' )
     *dst++ = *src;
    src++;
  }
 
  return buf;
}
 
int main (int argc, char **argv)
{
  char *in="Ha      llo   W e lt   ";
  char *out = eraseAllBlanks(in);
 
  printf("%s", out);
 
  free(out);

  getchar();
}

Ja, *str greift bis zum String-Ende - zu mindest wenn der String 0-Terminiert ist.

Wenn ein String 0-Terminiert ist, dann hat er am Ende eine 0 stehen. Daher ist die while-Bedingung korrekt.

EDIT: Zum free()-Thema. Es gibt ein paar Standard-Funktionen, die genauso arbeiten. str_dup() z.B. macht das genau so. Außerdem kann man eine Funktion auch kommentieren ;-)
 
Hallo,

könntest du nicht auch die C-String Funktion strtok verwenden?
C:
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
  char input[] = "Hal  lo We  lt   !";
  char chr[] = " ";

  printf("%s\n",input);

  char* token;
  token = (char*)strtok(input,chr);
  while(token != NULL){
     printf("%s",token);
     token = (char*)strtok(NULL,chr);
  }
  
  printf("\n");
  system("PAUSE");	
  return 0;
}

Ausgabe:
Code:
Hal  lo We  lt   !
HalloWelt!

Gruß Tom
 
Aufpassen beim Speicher reservieren, wenn der Ausgangsstring keine Leerzeichen enthält und somit gleich groß ist, wie der resultierende String.

C++:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char* eraseAllBlanks (const char *str)
{
    char *ret = (char*) malloc (strlen (str) + 1);  // strlen() gibt die Länge ohne \0 zurück daher +1
    int i;
    int j = 0;

    if (ret == NULL)
    {
        return NULL;
    }

    for (i = 0; i < strlen (str); i++)
    {
        if (str[i] != ' ')
        {
            ret[j] = str[i];
            j++;
        }
    }

    ret[j] = '\0';

    return ret;
}

int main()
{
    const char *in = "  W o  rd ";
    char *str = eraseAllBlanks (in);

    printf ("%s", str);

    free (str);
}
 
Zurück