Frage zu Zeigern in C

    • Frage zu Zeigern in C

      Das hier ist wohl eher eine Frage für ein Programmiererforum, da ich allerdings mitbekommen habe dass es hier im Board ein paar C-Spezialisten gibt ... ^^

      Ich habe vor ein paar Wochen angefangen mir C selber beizubringen und hab mir dazu das Buch C von A bis Z gekauft.
      Hab mich dann mal etwas mit dem reservieren von Speicher und mit Zeigern herumgespielt. So habe ich eine Funktion geschrieben die zwei Strings aneinanderhängt, und das reservieren von Speicher gleich automatisch vornimmt.

      Hier der Code:
      string_utils.h

      C-Quellcode

      1. #include <stdio.h>
      2. #include <stdlib.h>
      3. #include <string.h>
      4. char *strstick(char *str1, char *str2) {
      5. size_t len1=strlen(str1);
      6. size_t len2=strlen(str2);
      7. char tmp_str[len1+1];
      8. strcpy(tmp_str, str1);
      9. str1=(char *)malloc(len1+len2+1);
      10. strcpy(str1, tmp_str);
      11. str1=strcat(str1, str2);
      12. return str1;
      13. }
      Alles anzeigen


      string_test.c

      C-Quellcode

      1. #include <stdio.h>
      2. #include <stdlib.h>
      3. #include <string.h>
      4. #include "string_utils.h"
      5. int main() {
      6. char *string1="hallo";
      7. char *string2=" welt!";
      8. string1=strstick(string1, string2);
      9. printf("%s\n", string1);
      10. return EXIT_SUCCESS;
      11. }
      Alles anzeigen


      Es funzt auch so, nur hätte ich eigentlich so vorgehabt, dass ich den Rückgabewert von strstick() nicht extra der Variable string1 zuweisen muss - weil der Funktion ja der Zeiger übergeben wird!
      Was mache ich falsch, bzw. was habe ich noch nicht richtig verstanden?
    • Das Problem dabei ist folgendes: Pointer speichern ja im Prinzip nichts anderes als Adressen im Heap. Nehmen wir also an string1 zeigt auf die Adresse 0xAAAAAAAA und string2 zeigt auf 0xBBBBBBBB.
      Mit dem Funktionsaufruf werden beide Adressen auf den Stack geschrieben. Würdest du jetzt in dieser Funktion den Heap verändern, auf den zB string1 zeigt (also zB string1[0] = 'd'; ), dann hättest du die Änderung außerhalb der Funktion ebenfalls, da sich ja nur der Heap, nicht aber der Stack ändert.
      Du allerdings allokierst einen neuen Speicher (zB 0xCCCCCCCC) und weißt diesen string1 auf dem Stack zu. Dein string1 außerhalb der Funktion hat aber weiterhin 0xAAAAAAAA als Wert, da ja die Funktion strstick nicht auf den Stack von main zugreifen kann). Ergo bleibt dir nicht viel anderes übrig als die neue Adresse einfach als Rückgabewert zurückzugeben. Es gäbe zwar die Möglichkeit einen Pointer auf einen Pointer zu übergeben, das wird allerdings relativ selten genutzt.

      Btw.:
      Du verursachst in deinem Code ein Memory Leak, da du zwar Speicher allokierst, den aber nicht wieder freigibst. C hat keinen eingebauten Garbage Collector, da musst du dich leider selber um die Speicherverwaltung kümmern.
    • Ich würde an deiner stelle sowieso realloc() statt malloc() verwenden, weil du ja keinen neuen Speicher für die Var. string1 allokierst, sondern einfach nur Speicher hinzufügen willst.

      Und wie Nax schon gesagt hat, die beste Variante ist es einfach die neue Adresse als Rückgabewert zurückzugebeben.

      mfg
      James
      [Blockierte Grafik: http://dl.dropbox.com/u/24753690/stuff/forenlinks/rocketsign.png]
      Team Rocket - so schnell wie das Licht,
      gebt lieber auf und bekämpft uns nicht!

      join #teamrocket @iz-smart.net

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Stan ()

    • Ich merke gerade dass ich keinen Plan von der Funktionsweise von realloc() habe :(
      Mit calloc() krieg ich's halbwegs hin, aber realloc() gibt IMMER irgendwelche Fehler aus, meistens Segmentation fault (core dumped) :mpf:

      C-Quellcode

      1. #include <stdio.h>
      2. #include <stdlib.h>
      3. #include <string.h>
      4. #include "string_utils.h"
      5. int main() {
      6. char *string1="hallo";
      7. char *string2=" welt!";
      8. string1=strstick(string1, string2);
      9. printf("%s\n", string1);
      10. free(string1);
      11. return EXIT_SUCCESS;
      12. }
      Alles anzeigen

      C-Quellcode

      1. #include <stdio.h>
      2. #include <stdlib.h>
      3. #include <string.h>
      4. char *strstick(char *str1, char *str2) {
      5. char *tmp = str1;
      6. size_t len1=strlen(str1);
      7. size_t len2=strlen(str2);
      8. str1=(char *)calloc(len1+len2+1, sizeof(char));
      9. strcpy(str1, tmp);
      10. strcat(str1, str2);
      11. return str1;
      12. }
      Alles anzeigen


      Weiß jemand wie realloc() richtig anzuwenden ist?

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Christoph ()

    • void *realloc(void *zeiger, size_t neuegroesse);

      Das sagt die Hilfe von Visual Studio... (Hab die Parameternamen geändert)...

      Hoffe konnte dir helfen... wenn auch spät hab das Thema komplett vergessen
      James
      [Blockierte Grafik: http://dl.dropbox.com/u/24753690/stuff/forenlinks/rocketsign.png]
      Team Rocket - so schnell wie das Licht,
      gebt lieber auf und bekämpft uns nicht!

      join #teamrocket @iz-smart.net
    • Klar gibt's 'ne segmentation fault wenn du versuchst einen Speicherbereich freizugeben, der nicht dynamisch per malloc allokiert wurde. Das Problem ist, dass einer deiner Variablen auf "hallo" zeigt und du genau versuchst diesen Speicherbereich zu vergrößern. realloc macht nämlich mehr oder weniger nichts anderes als einen neuen, größeren Speicherbereich zu allokieren, den alten Inhalt zu kopieren und schließlich den alten Speicherbereich freizugeben.

      Hier mal ein kleines Codebeispiel zu realloc, damit du das besser verstehst:

      C-Quellcode

      1. #include <stdio.h>
      2. #include <malloc.h>
      3. #include <string.h>
      4. char* mycat (char *dst, const char *cat)
      5. {
      6. size_t length = strlen (dst) + strlen (cat);
      7. dst = realloc (dst, length + 2);
      8. strcat (dst, cat);
      9. return dst;
      10. }
      11. int main (int argc, char *argv[])
      12. {
      13. char *hello = malloc (strlen ("hello") + 1);
      14. strcpy (hello, "hello");
      15. hello = mycat (hello, " world");
      16. printf ("%s\n", hello);
      17. free (hello);
      18. return 0;
      19. }
      Alles anzeigen
    • Diese Zeile versteh ich nicht

      dst = realloc (dst, length + 2);

      Warum +2?

      +1 würde ja auch reichen oder?

      @Christoph

      Mhh... Da ich den Compiler nicht kenne, kann ich dir leider nicht sagen was die Fehlermeldung aussagt...
      James
      [Blockierte Grafik: http://dl.dropbox.com/u/24753690/stuff/forenlinks/rocketsign.png]
      Team Rocket - so schnell wie das Licht,
      gebt lieber auf und bekämpft uns nicht!

      join #teamrocket @iz-smart.net
    • As said, wenn man Elemente die nicht am Heap sind freigeben will, kommt üblicherweise so etwas raus.
      Du kannst ja normalerweise auch nicht folgendes machen:

      Quellcode

      1. int i = 1;
      2. free (&i);

      Da aber "Konstanten" wie "hello" und " world" üblicherweise nicht am Heap allokiert werden (-> üblicherweise werden sie gleich in den Code hineincompiliert, also liegen sozusagen da im RAM wo auch der Code liegt, der gerade ausgeführt wird...) darf man sie auch nicht mit free freigeben. Ein realloc macht allerdings mehr oder weniger nichts anderes als den alten Speicher, der ja in diesem Fall auf "hello" zeigt freizugeben. Ergo ist das nichts anderes als das Beispiel mit dem int oben.
      Wenn du allerdings "hello" wie in meinem Beispiel dynamisch allokierst gibt es keine Probleme mit realloc, da es ja das free auf einen dynamisch allokierten Speicher macht und es daher nicht zu einer Segmentation Fault kommt.
    • Ich weiß nicht ob es für Christoph so wichtig ist, aber free ist nur in C++ vorhanden. Also nicht in reinem C. Wenn er jetzt "nur" C lernen will, dann ist free nicht angebracht, sondern muss mit malloc oder mit realloc gemacht werden
      James
      [Blockierte Grafik: http://dl.dropbox.com/u/24753690/stuff/forenlinks/rocketsign.png]
      Team Rocket - so schnell wie das Licht,
      gebt lieber auf und bekämpft uns nicht!

      join #teamrocket @iz-smart.net
    • @Nax
      Vielen Dank für deine Antworten, ich werde mir das nochmal näher anschaun! :)

      Original von Stan
      Ich weiß nicht ob es für Christoph so wichtig ist, aber free ist nur in C++ vorhanden. Also nicht in reinem C. Wenn er jetzt "nur" C lernen will, dann ist free nicht angebracht, sondern muss mit malloc oder mit realloc gemacht werden

      Nach meinen Quellen ist das nicht korrekt, denn:
      Objektorientierte Programmierung - Prof. Dr. Bernhard Zimmermann

      In C/C++ gibt es für dynamische Datenelemente keine
      automatische Speicherverwaltung
      Explizite Freigabe des Speicherplatzes von nicht mehr
      benötigten dynamischen Datenelementen .
      Rückgabe des Speicherplatzes des dynamischen
      Datenelements eines Zeigers p
      – in C mit der Funktion free (Datei: <stdlib.h>)
      free(p);
      – in C++ mit dem delete-Operator
      delete p;

      Programmierregeln:
      Für eine Zeigergröße immer entweder malloc/free oder
      new/delete verwenden, nie gemischt, also z. B. nicht
      malloc/delete
      In C++-Programmen sollte möglichst new/delete benutzt
      werden.