Danke Danke:  0
Dislikes Dislikes:  0
Ergebnis 1 bis 11 von 11

Thema: [C Anfänger] Pointer

  1. #1

    Registriert seit
    05.12.15
    Danke (erhalten)
    6
    Gefällt mir (erhalten)
    15

    Standard [C Anfänger] Pointer

    Anzeige
    Hey,

    ich wollte eine Funktion schreiben, die zwei Zeichenketten miteinander tauscht. Dabei dachte ich mir: Tausche doch einfach die Pointer. Mein Code:

    Code:
    #include <stdio.h>
    
    void tausche(char *text1, char *text2)
    {	
    	printf("%u %u\n", *text1,*text2);
    	int temp = *text1;
    	*text1 = *text2;
    	*text2 = temp;
    	printf("%u %u\n", *text1,*text2);
    }
    
    int main()
    {
    	char text1[] = "Hallo1", text2[] = "Hallo2";
    	
    	// printf("text1: %s\ntext2: %s\n", text1, text2);
    	tausche(text1, text2);
    	// printf("text1: %s\ntext2: %s\n", text1, text2);
    	return 0;
    }
    sollte theoretisch funktionieren, tut er auch, aber es gilt von vornherein "*text1 = 72 = *text2" was ich nicht ganz nachvollziehen kann. Offenbar klappt das wechseln der Pointer nicht?
    Geändert von Shalec (20.04.17 um 21:54 Uhr)

  2. #2
    Moderator Avatar von CDW
    Registriert seit
    20.07.05
    Danke (erhalten)
    34
    Gefällt mir (erhalten)
    846

    Standard

    Zitat Zitat von Shalec Beitrag anzeigen
    sollte theoretisch funktionieren, tut er auch, aber es gilt von vornherein "*text1 = 72 = *text2" was ich nicht ganz nachvollziehen kann.
    ändere mal
    Code:
    char text1[] = "Hallo1", text2[] = "Hallo2";
    zu 
    char text1[] = "Xallo1", text2[] = "Hallo2";
    und lass es noch mal laufen
    Offenbar klappt das wechseln der Pointer nicht?
    Du vertauscht in Deinem Code nicht die Pointer, sondern schon Werte im Speicher ("Hello"), auf die diese Pointer zeigen.

    Code:
    #include <stdio.h>
    
    void tausche(char **text1, char **text2) /*nimmt einen Pointer auf Pointer entgegen, 
                                                                d.h text1,text2 sind lokale Variable, die auf einen Pointer zeigen */
    {	
    	char *temp = *text1;
    	*text1 = *text2;
    	*text2 = temp;
    }
    
    int main()
    {
    	char *text1 = "Hallo1", *text2 = "Hallo2";
    	printf("text1: %s\ntext2: %s\n", text1, text2);
    	tausche(&text1, &text2);  /* um Pointer vertauschen zu können, braucht die Funktion logischerweise deren Adressen und nicht den Inhalt ;) */
    	printf("text1: %s\ntext2: %s\n", text1, text2);
    	return 0;
    }
    Noch mal, für alle Pseudo-Geeks: 1+1=0. -> 10 wäre Überlauf!
    Selig, wer nichts zu sagen hat und trotzdem schweigt.

  3. #3

    Registriert seit
    05.12.15
    Danke (erhalten)
    6
    Gefällt mir (erhalten)
    15

    Standard

    Das man auch **text1 schreiben kann, wusste ich gar nicht Mit deiner Variante kann ich jetzt erstmal weiter verstehen, warum das so funktioniert.

    Mal eine Frage zum internen: Es gibt ja auch eine Funktion strcpy (oder so), mit der man eben auch die Strings tauschen kann. Arbeitet diese Funktion ähnlich wie das hier? Oder ist sie effizienter?

    Also nochmal
    Code:
    char s[]
    erzeugt einen Array und

    Code:
    char *s
    einen Pointer auf den Speicher.

    Wenn ich im Netz nach den Unterschieden google ( string - What is the difference between char s[] and char *s in C? - Stack Overflow ) dann besteht nur darin der Unterschied, dass ich
    Code:
    s[0]='J';
    belegen darf, was im Falle *s nicht ginge.

    Wie würde ich denn die Funktion schreiben, wenn ich char s[] verwende? Geht das überhaupt ohne strcpy?
    Geändert von Shalec (21.04.17 um 12:13 Uhr)

  4. #4
    Moderator Avatar von CDW
    Registriert seit
    20.07.05
    Danke (erhalten)
    34
    Gefällt mir (erhalten)
    846

    Standard

    Zitat Zitat von Shalec Beitrag anzeigen
    Das man auch **text1 schreiben kann, wusste ich gar nicht
    Es geht auch mehr ***text1 (pointer-auf-pointer-auf-pointer) usw.

    Mal eine Frage zum internen: Es gibt ja auch eine Funktion strcpy (oder so), mit der man eben auch die Strings tauschen kann. Arbeitet diese Funktion ähnlich wie das hier? Oder ist sie effizienter?
    Das sind verschiedene paar Schuhe.
    str(n)cpy wird den Inhalt des char-arrays (aka "Speicherbereich") kopieren.
    Und "tausche" vertauscht nur die Werte der Zeiger auf diese Arrays (Speicherbereiche), denn so hatte ich dein Anliegen verstanden




    Wie würde ich denn die Funktion schreiben, wenn ich char s[] verwende? Geht das überhaupt ohne strcpy?
    Vom Datentyp ist ein Array doch etwas anderes als ein Pointer. Ein Arraybezeichner kann zudem (afaik) kein modifizierbares lvalue (L-value - Wikipedia) sein, daher sollte diese Trickserei mit dem (direkten) Vertauschen der Adressen nicht klappen. Allerdings ist diese nur bei Spielereien interessant , da man ja auch soetwas machen kann:
    Code:
    #include <stdio.h>
    
    void tausche(char **text1, char **text2) /*nimmt einen Pointer auf Pointer entgegen, 
                                                                                                          d.h text1,text2 sind lokale Variable, die auf einen Pointer zeigen */
    {
        char *temp = *text1;
        *text1 = *text2;
        *text2 = temp;
        }
    
    int main()
      {
          char text1[] = "Hallo1 Welt1", text2[] = "Hallo2 Welt2";
          char *t1 = &text1[0], *t2 = &text2[0];
          printf("text1: %s\ntext2: %s\n", t1, t2);
          
          tausche(&t1, &t2);  /* um Pointer vertauschen zu können, braucht die Funktion logischerweise deren Adressen und nicht den Inhalt ;) */
          printf("text1: %s\ntext2: %s\n", t1, t2);
          return 0;
          }
    Geändert von CDW (23.04.17 um 00:11 Uhr) Grund: "Vom Datentyp und Interna" umformuliert
    Noch mal, für alle Pseudo-Geeks: 1+1=0. -> 10 wäre Überlauf!
    Selig, wer nichts zu sagen hat und trotzdem schweigt.

  5. #5

    Registriert seit
    05.12.15
    Danke (erhalten)
    6
    Gefällt mir (erhalten)
    15

    Standard

    Wie ich sehe, ist dieser Trick aber dann nicht für text1[] und 2 funktionierend. Gut. Ich muss in jedem Fall noch ein wenig über die Pointer nachdenken, aber ich denke, dass das Konzept gut nachvollziehbar ist. (Sollte ja logisch sein )

    Dann erstmal vielen Dank für die Hilfestellungen und Erklärungen. Mein Vorhaben habe ich übrigens in nem Buch entdeckt. Deren Lösung ist das über strcpy zu lösen. Ich dachte aber, dass man, wie bei Integern, die Pointer umdefinieren kann. Sollte auch (logischer Weise) bei gleichlangen Arrays funktionieren, aber hier könnte der Aufbau eines Arrays widersprechen. Meine Idee ist eben gewesen, dass ein Objekt char s[10] (11 stelliger Character-Array?) so aufgebaut ist: Zeiger auf Speicherstart mit dem Wert s[0]. s[1] (und generall s[i++]) verweist dann auf &s[0]++. Als Lösung habe ich dann erdacht (zum Tauschen), dass man entsprechend &s[0] auf &t[0], für char t[10], umdefinieren kann.
    Aber dann ist eben noch die Idee da, dass irgendwo hinterlegt sein muss, wie lang der Array ist, womit dann der Speicher nicht mehr von &s[0] bis &s[0]+11 reicht, sondern offenbar noch größer sein muss. (Wie viel Byte verbrauch ein Array insgesamt?)

    Aber ich glaube, dass für mein Vorhaben das detaillierte Wissen darüber nicht unbedingt notwendig ist. Ich will insgesamt mit wirklich großen Zahlen arbeiten (>15120-Bit) bzw. Punkten auf Kurven, mit einer Basis-punkt-größe (Erzeuger) von ca. 256-521-Bit.

  6. #6
    Moderator Avatar von CDW
    Registriert seit
    20.07.05
    Danke (erhalten)
    34
    Gefällt mir (erhalten)
    846

    Standard

    Zitat Zitat von Shalec Beitrag anzeigen
    Meine Idee ist eben gewesen, dass ein Objekt char s[10] (11 stelliger Character-Array?) so aufgebaut ist: Zeiger auf Speicherstart mit dem Wert s[0]. s[1] (und generall s[i++]) verweist dann auf &s[0]++.
    Ich bin nicht sicher ob ich dich richtig verstanden habe. Aber streng gesehen ist [] in dem Kontext ein Operator und s[0] (und generell s[n]) ist 'ne Array-subscription.
    Ich hab' jetzt mal nachgeschlagen:
    Zitat Zitat von ISO/IEC 9899:TC3
    A postfix expression followed by an expression in square brackets [] is a subscripted
    designation of an element of an array object. The definition of the subscript operator []
    is that E1[E2] is identical to (*((E1)+(E2))). Because of the conversion rules that
    apply to the binary + operator, if E1 is an array object (equivalently, a pointer to the
    initial element of an array object) and E2 is an integer, E1[E2] designates the E2-th
    element of E1 (counting from zero).
    Grob gesagt, array object ist ein (nicht modifizierbarer) Pointer auf das erste Element, Zugriff auf die anderen Elemente erfolgt über (Zeiger)arithmetik (pointer + X).

    Aber dann ist eben noch die Idee da, dass irgendwo hinterlegt sein muss, wie lang der Array ist,
    *hust* this is Sparta C. Die Größe des konstanten Arrays ist dem Compiler bekannt, aber (implizit) hinterlegt wird das nirgendwo - sonst gäbe es nicht so viele buffer-overflow Lücken
    Noch mal, für alle Pseudo-Geeks: 1+1=0. -> 10 wäre Überlauf!
    Selig, wer nichts zu sagen hat und trotzdem schweigt.

  7. Gefällt mir bitmuncher liked this post
  8. #7

    Registriert seit
    05.12.15
    Danke (erhalten)
    6
    Gefällt mir (erhalten)
    15

    Standard

    Hey,
    sowas in der Richtung habe ich gestern Abend auch kurz gelesen. Ein Array, sagen wir char s[3]="abc" ist so aufgebaut, dass
    {
    0 => 'a',
    1 => 'b',
    2 => 'c',
    '\0'}
    wobei die binäre 0 (d.h. '\0') das Ende des Arrays angibt. Also gibt es wohl ein "Break" Argument (sonst würde ja while(s[x]) für x++ eine Endlosschleife liefern) aber die exakte Größe ist nicht unbedingt bekannt.

    Es gibt doch sicherlich auch Befehle, die die Länge des Arrays zurückgeben. Gibt es für solche Befehle auch Speedanalysen? (In cycles/op, Ausgaben in µs sind ja Hardware abhängig.) Oder allgemeiner: Gibt es irgendwo eine Seite, die solche Analysen sammeln?

  9. #8
    Moderator Avatar von CDW
    Registriert seit
    20.07.05
    Danke (erhalten)
    34
    Gefällt mir (erhalten)
    846

    Standard

    Zitat Zitat von Shalec Beitrag anzeigen
    Also gibt es wohl ein "Break" Argument (sonst würde ja while(s[x]) für x++ eine Endlosschleife liefern) aber die exakte Größe ist nicht unbedingt bekannt.
    Ist eher eine Konvention bezüglich der Strings (denn man kann Arrays auch für andere Dinge nutzen )
    Und Endlosschleife wäre schön. Viel eher bekommt man aber eine SEGV/Access Violation nach dem verlassen des gültigen Speicherbereiches. Und falls in "while(s[x]) foo" noch der Inhalt modifiziert wurde - eine potentiell ausnutzbare Sicherheitslücke.

    Es gibt doch sicherlich auch Befehle, die die Länge des Arrays zurückgeben.
    Code:
    sizeof(myarr)/sizeof(myarr[0])
    Falls die Länge zur Compilierungszeit bekannt ist. Ansonten muss man entweder explizit speichern oder bei Strings "zählen" (strlen).

    Gibt es für solche Befehle auch Speedanalysen? (In cycles/op, Ausgaben in µs sind ja Hardware abhängig.) Oder allgemeiner: Gibt es irgendwo eine Seite, die solche Analysen sammeln?
    Die Performance ist Compiler und Bibliothekabhängig. Einfach mal zum Vergleich:
    Comparison of C/POSIX standard library implementations for Linux
    Code:
    Performance comparison	musl	uClibc	dietlibc	glibc
    Tiny allocation & free	0.005	0.004	0.013	0.002
    Big allocation & free	0.027	0.018	0.023	0.016
    Allocation contention, local	0.048	0.134	0.393	0.041
    Allocation contention, shared	0.050	0.132	0.394	0.062
    Zero-fill (memset)	0.023	0.048	0.055	0.012
    String length (strlen)	0.081	0.098	0.161	0.048
    Zum einen kann man einfach "timen": http://www.google.de/search?q=c+timing+bench&btnG=Suche
    Ansonsten wäre das Stichwort "profiling" (z.B. gcc -pg)
    Code:
    % gcc -Wall -Wextra -pg  main.c -o habo
    % gprof habo habo.gmon|more
    ...
      %   cumulative   self              self     total           
     time   seconds   seconds    calls  ms/call  ms/call  name    
      0.0       0.00     0.00       34     0.00     0.00  __vfprintf [646]
      0.0       0.00     0.00       29     0.00     0.00  arena_run_split [1]
      0.0       0.00     0.00       14     0.00     0.00  arena_avail_remove [2]
      0.0       0.00     0.00       13     0.00     0.00  memcpy [3]
      0.0       0.00     0.00       12     0.00     0.00  memchr [4]
      0.0       0.00     0.00       11     0.00     0.00  __malloc [647]
      0.0       0.00     0.00        8     0.00     0.00  __fflush [648]
      0.0       0.00     0.00        8     0.00     0.00  arena_avail_insert [5]
      0.0       0.00     0.00        6     0.00     0.00  __sfvwrite [649]
      0.0       0.00     0.00        4     0.00     0.00  __jemalloc_choose_arena_hard [650]
      0.0       0.00     0.00        4     0.00     0.00  __swrite [651]
      0.0       0.00     0.00        4     0.00     0.00  _once [652]
      0.0       0.00     0.00        4     0.00     0.00  _swrite [653]
      0.0       0.00     0.00        4     0.00     0.00  _write [654]
      0.0       0.00     0.00        4     0.00     0.00  localeconv_l [6]
      0.0       0.00     0.00        4     0.00     0.00  strlen [7]
      0.0       0.00     0.00        4     0.00     0.00  vfprintf [8]
      0.0       0.00     0.00        4     0.00     0.00  vfprintf_l [9]
      0.0       0.00     0.00        3     0.00     0.00  __jemalloc_arena_malloc_large [655]
      0.0       0.00     0.00        3     0.00     0.00  arena_run_alloc_helper [10]
      0.0       0.00     0.00        3     0.00     0.00  jemalloc_constructor [11]
      0.0       0.00     0.00        2     0.00     0.00  __smakebuf [656]
    und/oder entsprechende Tools: Valgrind – Wikipedia die das messen.
    so schaut's aus   




    Allgmein zum Thema Optimierung fällt mir Software optimization resources. C++ and assembly. Windows, Linux, BSD, Mac OS X ein.
    Angehängte Grafiken Angehängte Grafiken
    Noch mal, für alle Pseudo-Geeks: 1+1=0. -> 10 wäre Überlauf!
    Selig, wer nichts zu sagen hat und trotzdem schweigt.

  10. Gefällt mir Shalec liked this post
  11. #9
    Moderator
    Registriert seit
    30.06.08
    Danke (erhalten)
    27
    Gefällt mir (erhalten)
    827

    Standard

    Etwas OT..

    Vom Datentyp und Interna ist ein Array doch etwas anderes als ein Pointer.
    "Damals" war es so, dass ein Verweis auf einen bestimmten Vektor, z.B. a[2] intern zum Zeiger wird, nämlich *(zeiger_auf_a+2).
    Und zwar bei allen Adressierungen und unabhaengig vom Typ: Es wird (fuers in/dekrement) lediglich die Größe des Typs berücksichtigt, denn intern ist a[3] dann *(zeiger_auf_a+(3*Typegröße_von_a). Man kann (oder konnte?) auch statt a[2], genausogut *(a+2) schreiben was die Tatsache noch deutlicher hat (gilt sogar für &a[1]).

    Unterschiede hatte man während des schreibens, denn ein Zeiger gilt als Variable auf den man alle möglichen Operatoren anwenden kann während ein Arrayname als Konstante gehandhabt wird.

    Allerdings beziehe ich mich auf die Doku von Kernighan/Richtie selbst, also ist es möglich dass sich da was gaendert hat - ist zwar OT aber vielleicht kann da jemand was abschliessendes zu sagen?
    Wenn ein Gesetz nicht gerecht ist, dann geht die Gerechtigkeit vor dem Gesetz!

    Habo Blog - http://blog.hackerboard.de/

  12. #10
    Moderator Avatar von CDW
    Registriert seit
    20.07.05
    Danke (erhalten)
    34
    Gefällt mir (erhalten)
    846

    Standard

    Zitat Zitat von Chromatin Beitrag anzeigen
    "Damals" war es so, dass ein Verweis auf einen bestimmten Vektor, z.B. a[2] intern zum Zeiger wird, nämlich *(zeiger_auf_a+2).
    Streiche "Interna" aus der Aussage (ich habe es jetzt wegeditiert) weil es falsch ist bzw. im Kontext der Syntax gemeint war. Man kann nämlich sowas machen:
    Code:
    #include <stdio.h>
    
    void tausche(char **text1, char **text2) {
      char *temp = *text1;
      *text1 = *text2;
      *text2 = temp;
    }
    
    int main() {
      char text1[] = "Hallo1 Welt1", text2[] = "Hallo2 Welt2";
      char *t1 = text1, *t2 = text2;
    
      tausche(&t1, &t2);
      puts("tausche(&t1,&t2)");
      printf("t1: %s | t2: %s\n", t1, t2);
      printf("text1: %s | text2 %s\n", text1, text2);
    
      tausche(&text1, &text2);
      puts("tausche(&text1, &text2)");
      printf("t1: %s | t2: %s\n", t1, t2);
      printf("text1: %s, text2  %s\n", text1, text2);
      return 0;
    }
    und der Compiler schluckt das (wenn auch mit Warnungen). Das Ergebnis des zweiten Tauschs kann aber "überraschend" sein:
    Code:
    % gcc -O2 main.c -o habo && ./habo                                                                                 [138] 
    tausche(&t1,&t2)
    t1: Hallo2 Welt2 | t2: Hallo1 Welt1
    text1: Hallo1 Welt1 | text2 Hallo2 Welt2
    
    tausche(&text1, &text2)
    t1: Hallo1 Welt2 | t2: Hallo2 Welt1
    text1: Hallo2 Welt1, text2  Hallo1 Welt2
    @Threadersteller: das schaut ein wenig nach Korintenkack^W Haarspalterei und Klugdefäkation aus, aber wenn auch C auf den ersten Blick einfach ausschaut, so gibt es viele kleine Teufelchen, die in den Details stecken - siehe z.B das Beispiel oben
    Ein weiters Beispiel und Stolperfalle wäre "int propagation":
    Value Range Propagation | Dr Dobb's


    denn intern ist a[3] dann *(zeiger_auf_a+(3*Typegröße_von_a). Man kann (oder konnte?) auch statt a[2], genausogut *(a+2) schreiben was die Tatsache noch deutlicher hat (gilt sogar für &a[1]).
    Sofern man die Definition des Standards nimmt, scheint sich das nicht geändert zu gaben:
    The definition of the subscript operator []
    is that E1[E2] is identical to (*((E1)+(E2)))
    Noch mal, für alle Pseudo-Geeks: 1+1=0. -> 10 wäre Überlauf!
    Selig, wer nichts zu sagen hat und trotzdem schweigt.

  13. Gefällt mir Chromatin liked this post
  14. #11

    Registriert seit
    05.12.15
    Danke (erhalten)
    6
    Gefällt mir (erhalten)
    15

    Standard

    Anzeige
    Also ich verstehe mittlerweile den Zusammenhang zwischen Pointern (denke ich jedenfalls ^^)

    Kurze Zwischenbemerkung: Das Buch, mit dem ich die Grundlagen erlese, notiert immer
    Code:
    main(){
        // Funktion
    }
    Wenn ich sowas ausführen wollen würde, bekäme ich einen Error.

    Also zum Thema Pointer, laut dem Buch habe ich
    Code:
    void main(){
        int zahl = 1234, *ptr;
        ptr = &zahl; // speichert Adresse von zahl in ptr
        printf("%i\n",*ptr); // Zeigt den Wert, der in der Adresse "ptr" gespeichert ist. 
    }
    Soweit gut. Wie würde ich nun den Pointer auf einen Pointer, also **ptr , verarbeiten?
    Nach obiger Logik wäre *ptr die Adresse und **ptr der Wert in *ptr. Demzufolge macht es recht selten Sinn ptr, *ptr und **ptr im selben Zuge zu verwenden?

Ähnliche Themen

  1. pointer valid ?
    Von FILE im Forum Code Kitchen
    Antworten: 4
    Letzter Beitrag: 11.04.09, 17:19
  2. Out Pointer
    Von shinobo im Forum Code Kitchen
    Antworten: 2
    Letzter Beitrag: 03.04.09, 15:55
  3. C++ Pointer
    Von Kenniej91 im Forum Code Kitchen
    Antworten: 6
    Letzter Beitrag: 10.11.07, 21:12
  4. Pointer von Struktur übergeben
    Von houdini2 im Forum Code Kitchen
    Antworten: 2
    Letzter Beitrag: 06.11.04, 18:22
  5. Pointer usw :)
    Von CusHi0n im Forum Code Kitchen
    Antworten: 2
    Letzter Beitrag: 05.10.04, 10:33

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •