Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

AF1

Frischling

  • »AF1« ist der Autor dieses Themas
  • Private Nachricht senden

1

19.06.2011, 20:18

[C++] Zeiger: Verständnisfragen

Hallo,

bin zwar neu hier, aber hätte ein paar Fragen zu Zeigern, wäre euch sehr dankbar, wenn ich mir diese beantworten könntet, da ich das noch nicht (ganz) verstehe.

Es reichen auch simple Ja/Nein.

Bitte korrigieren, wenn was falsch ist. :)
Und sorry wenn es sich hier um triviale Dinge handelt, hatte aber vorher nie C++/Zeigern zu tun.

Und eine Frage vorab, welche Schreibweise empfiehlt ihr?
int* pointer;
int * pointer;
int *pointer;
Ich weiß, dass das alles gleich ist, aber vielleicht gibt es da eine bevorzugte Schreibweise?

C-/C++-Quelltext

1
2
3
int i = 11;
int *ip; // ip ist ein Zeiger auf einen int-Wert
ip = &i; // ip zeigt auf die Adresse von i 


Ist dieser Code äquivalent zu:

C-/C++-Quelltext

1
2
int i = 11;
int *ip = &i;

?
Das verwirrt mich etwas, denn normal wäre ja z. B. *ip = 100; aber hier wird die Adresse von i "gespeichert".
Also kann man die zweite Schritte int *ip; ip = &i; in einem zusammenfassen: int *ip = &i. Sehe ich das richtig so?


C-/C++-Quelltext

1
2
3
4
5
6
7
double d[10] = {1,2,3,4,5,6,7,8,910};
double *dp1 = d; // mit d übergibt man den Anfang des arrays? Wieso nicht &d?
cout << dp1 << endl; // wäre dann die Adresse von d[0].
cout << *dp1 << endl; // wäre dann d[0], in diesem Falle 1.

double *dp2 = dp1 + 1; // dp2 zeigt auf Adresse von a[1]? 
cout << dp2 - dp1 << endl; // Adresse von a[1] - Adresse von a[0] = 1?



C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
const int n = 10;
int a[n+1];
int key = 6; 
int i;


a[n] = key;
int *p = a;
while(*p++ != key); // Solange der Wert von der Adresse auf die p zeigt ungleich key, inkrementiere die Adresse auf die p zeigt um eins? Müsste nicht *(p++) stehen, sonst könnte man doch meinen dass der Wert von der Adresse auf die p zeigt inkrementiert wird? 

i = p - a - 1; // Wieso hier -1?


C-/C++-Quelltext

1
2
matrix[i][j] // Zweidimensionales Array
matrix[i, j] // Was ist das?


Dann noch mehr Fragen - zu C-Zeichenketten.

C-/C++-Quelltext

1
2
3
4
5
6
char *str = "ABC"; // Zeiger zeigen doch auf Adressen, wieso wird hier "ABC" "zugewiesen"? 
// Oder gilt hier char *str == char str[]? 
cout << str; // Ausgabe: ABC. Wieso ABC? 
int i = 1;
cout << str[i]; // Ausgabe: B. Wieso kann hier bei str auf eine Stelle zugegriffen werden, wie bei einem Array? 
cout << *(str + i); // Ausgabe: B. Hier das gleiche.



C-/C++-Quelltext

1
2
3
4
5
6
char *str = "Irgend ein Text."; 
char *tmp = str; // tmp zeigt auf str und str zeigt auf "Irgend ein Text."? 
int len = 0;
while(*tmp++) // Wieso nicht *str++? 
     len++;
cout << "Laenge des Strings " << str << " = " << len << endl;



C-/C++-Quelltext

1
2
3
char *original = "Irgend ein Text.";
char *duplikat; 
duplikat = original; // Wäre hier auch char *duplikat = original möglich?



C-/C++-Quelltext

1
2
3
4
5
6
7
/* C-Strings kopieren */
char *source = "Irgend ein Text.";
char dest[80];

char *s = source; 
char *d = dest; 
while (*d++ = *s++); // Was muss denn hier passieren, damit es abgebrochen wird?



C-/C++-Quelltext

1
2
3
4
5
6
7
8
char *sa[] = {"eins\n", "zwei\n"}; // Wieso hier noch der *? Ist das char sa[][] bzw. char **sa? 
char **sp = sa; // Wie wäre das in 2 Schritten? char **sp; sp = sa? 
cout << sa[0]      << endl; // eins
cout << *sa         << endl; // eins
cout << sa[1]      << endl; // zwei
cout << sa[1][0] << endl; // z
cout << *sp        << endl; // eins
cout << sp[1]     << endl; // zwei



C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include 
using namespace std;

struct Person
{
      char name[80], address[80];
      double salary;
};
Person person[50];

void printperson(Person const &p)
{
      cout << "Name: " << p.name << endl;
      cout << Adress: " << p.address << endl;
}

Person const &getperson(int index) // Was soll hier das & bei getperson bedeuten/bringen? 
{
      // ...
      return person[index];
}

int main()
{
      Person boss;

      printperson(boss);
      printperson(getperson5));
}



Dann habe ich hier noch einen längeren Quellcode mit paar Fragen.

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#include <iostream>
#include <stddef.h>

using namespace std;

// Liefert die Anzahl der Zeichen, die in s enthalten sind. Das abschließende Null-Byte wird nicht mitgezählt.
size_t my_strlen(const char *s);

// Kopiert die Zeichenkette src Zeichen für Zeichen in die Zeichenkette dest. Das abschließende Null-Byte wird auch kopiert. Liefert dest als Funktionsewert zurück.
char *my_strcpy(char *dest, const char *src);

// Hängt eine Kopie der zeichenkette src an die zeichenkette dest an. Liefert dest als Funktionswert zurück.
char *my_strcat(char *dest, const char *src);

// Liefert einen Zeiger auf das erste Vorkommen des Zeichens in der Zeichenkette s zurück oder aber NULL, falls c nicht in s enthalten ist.
char *my_strchr(const char *s, char c);

// Vergleicht die Zeichenketten s1 und s2; liefert einen Wert <0, wenn s10, wenn s1>s2 ist. 
int my_strcmp(const char *s1, const char *s2);


int main (int argc, char * const argv[]) 
{
    const char *str1 = "Wie man sich bettet, so liegt man.";
    const char *str2 = "Wie man in den Wald hineinruft, so schallt es heraus.";
    char ziel[256];
    char *tmp;
    
    cout << "Die Zeichenkette \"" << str1 << "\" enthaelt " 
    << my_strlen(str1) << " Zeichen.\n" << endl;
    
    my_strcpy(ziel,str1);
    cout << ziel << "\n" << endl;
    
    my_strcpy(ziel+21, str2+32);
    cout << ziel << "\n" << endl;
    
    my_strcat(ziel, " ");
    my_strcat(ziel, str2);
    cout << ziel << "\n" << endl;
    
    tmp = my_strchr(ziel, ',');
    cout << (tmp == NULL?"NULL":tmp) << endl;
    tmp = my_strchr(ziel, 'S');
    cout << (tmp == NULL?"NULL":tmp) << "\n" << endl;
    
    cout << my_strcmp(str1, str2) << endl;
    
    return 0;
}


size_t my_strlen(const char *s)
{
    const char *p = s; // Was genau passiert hier? Worauf zeigt p? 
    
    while(*++p); 
    
    return p-s;
}


char *my_strcpy(char *dest, const char *src) // Wofür ist der * bei my_strcpy? 
{   
    char *temp = dest;
    while(*dest++ = *src++);
    
    return temp;
}


char *my_strcat(char *dest, const char *src)
{
    char *temp = dest; 
    
    while(*dest)
        dest++;
    
    while(*dest++ = *src++);
    
    return temp; // Wieso nicht return dest? 
}


char *my_strchr(const char *s, char c)
{
    while(*s)
    {
        if(*s==c)
            return const_cast<char*>(s); // s ist doch schon const char*? Wofür das Casten? 
        s++;
    }
    return NULL;
}


int my_strcmp(const char *s1, const char *s2)
{
    for(; *s1 == *s2; s1++, s2++)
        if(*s1 == '\0')
            return 0;
    return *s1 - *s2;
}


Danke schonmal.

VG AF1.

JRJ

Treue Seele

Beiträge: 113

Wohnort: Tirol

Beruf: Schüler

  • Private Nachricht senden

2

19.06.2011, 22:28

Das sind ja viele Fragen 8|.

  1. Ich verwende int *pointer;
    Das ist aber reine Geschmackssache.
  2. Ja
  3. Ja
  4. *p++ funktioniert, weil der ++ Operator vor dem * Operator behandelt wird. Operatoren Rangfolge

    C-/C++-Quelltext

    1
    
    i = p - a - 1;
    Kann nicht funktionieren weil i eine Variable ist p und a aber Zeiger. Oder liege ich hier falsch?

  5. C-/C++-Quelltext

    1
    
    matrix[i, j]
    Das ist gar nix.

  6. C-/C++-Quelltext

    1
    
    char *str = "ABC";
    Diese Zeile ist sehr gefährlich!!! 8o Weil str irgendwo in deinen Speicher zeigt aber du weißt nicht wohin.

    Oder gilt hier char *str == char str[]?
    Nicht ganz. Mit str[] wird Speicher reservierst, mit *str nicht!

    C-/C++-Quelltext

    1
    
    cout << str; // Ausgabe: ABC. Wieso ABC?
    Weil str auf einen Speicherbereich zeigt in dem ABC\0 steht.
    Das \0 dient dazu um zu signalisieren dass der String aus ist.

    C-/C++-Quelltext

    1
    2
    3
    
    int i = 1;
    cout << str[i]; // Ausgabe: B. Wieso kann hier bei str auf eine Stelle zugegriffen werden, wie bei einem Array? 
    cout << *(str + i); // Ausgabe: B. Hier das gleiche.


    C-/C++-Quelltext

    1
    
    str[i] == *(str + i)   //Sind gleichwertig!

    C-/C++-Quelltext

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    Speicher:
    
    | A | B | C |\0|
     /\
     str  //str zeigt auf das A  
    
    | A | B | C |\0|
         /\
       str+1  //str zeigt auf das B
    Mit Zeigern kannst du rechnen wie mit normalen Zahlen. Bei str+2 hüpft der Zeiger 2 Speicherzellen weiter und zeigt daher auf einen anderen Wert. Hier: C

  7. C-/C++-Quelltext

    1
    2
    3
    4
    5
    6
    
    char *str = "Irgend ein Text."; 
    char *tmp = str; //Hier zeichen str und tmp auf "Irgend ein Text."
    int len = 0;
    while(*tmp++) // *str++ funktioniert auch
         len++;
    cout << "Laenge des Strings " << str << " = " << len << endl;


  8. C-/C++-Quelltext

    1
    2
    3
    
    char *original = "Irgend ein Text.";
    char *duplikat; 
    duplikat = original; // Wäre hier auch char *duplikat = original möglich?
    JA

  9. C-/C++-Quelltext

    1
    2
    3
    4
    5
    6
    7
    
    /* C-Strings kopieren */
    char *source = "Irgend ein Text.";
    char dest[80];
    
    char *s = source; 
    char *d = dest; 
    while (*d++ = *s++); // Was muss denn hier passieren, damit es abgebrochen wird?
    Die while-Schleife läuft durch und kommt ihrgendwann zum \0.
    In C und C++ ist 0 = false und alles >0 = true;
    Die Schleife läuft so lange bis in den Klammern ein wahrer Ausdruck steht. Wenn die while-Schleife zum \0 kommt bricht sie ab.

  10. C-/C++-Quelltext

    1
    2
    3
    4
    5
    6
    7
    8
    
    char *sa[] = {"eins\n", "zwei\n"}; // Wieso hier noch der *? Ist das char sa[][] bzw. char **sa?         JA
    char **sp = sa; // Wie wäre das in 2 Schritten? char **sp; sp = sa?                                      Würde Funktionieren
    cout << sa[0]      << endl; // eins
    cout << *sa         << endl; // eins
    cout << sa[1]      << endl; // zwei
    cout << sa[1][0] << endl; // z
    cout << *sp        << endl; // eins
    cout << sp[1]     << endl; // zwei


  11. C-/C++-Quelltext

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    
    #include 
    using namespace std;
    
    struct Person
    {
          char name[80], address[80];
          double salary;
    };
    Person person[50];
    
    void printperson(Person const &p)
    {
          cout << "Name: " << p.name << endl;
          cout << Adress: " << p.address << endl;
    }
    
    Person const &getperson(int index) // Was soll hier das & bei getperson bedeuten/bringen?      //getperson gibt eine Referenz zurück.
    {
          // ...
          return person[index];
    }
    
    int main()
    {
          Person boss;
    
          printperson(boss);
          printperson(getperson5));
    }
    Referenz

  12. C-/C++-Quelltext

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    
    #include <iostream>
    #include <stddef.h>
    
    using namespace std;
    
    // Liefert die Anzahl der Zeichen, die in s enthalten sind. Das abschließende Null-Byte wird nicht mitgezählt.
    size_t my_strlen(const char *s);
    
    // Kopiert die Zeichenkette src Zeichen für Zeichen in die Zeichenkette dest. Das abschließende Null-Byte wird auch kopiert. Liefert dest als Funktionsewert zurück.
    char *my_strcpy(char *dest, const char *src);
    
    // Hängt eine Kopie der zeichenkette src an die zeichenkette dest an. Liefert dest als Funktionswert zurück.
    char *my_strcat(char *dest, const char *src);
    
    // Liefert einen Zeiger auf das erste Vorkommen des Zeichens in der Zeichenkette s zurück oder aber NULL, falls c nicht in s enthalten ist.
    char *my_strchr(const char *s, char c);
    
    // Vergleicht die Zeichenketten s1 und s2; liefert einen Wert <0, wenn s10, wenn s1>s2 ist. 
    int my_strcmp(const char *s1, const char *s2);
    
    
    int main (int argc, char * const argv[]) 
    {
        const char *str1 = "Wie man sich bettet, so liegt man.";
        const char *str2 = "Wie man in den Wald hineinruft, so schallt es heraus.";
        char ziel[256];
        char *tmp;
        
        cout << "Die Zeichenkette \"" << str1 << "\" enthaelt " 
        << my_strlen(str1) << " Zeichen.\n" << endl;
        
        my_strcpy(ziel,str1);
        cout << ziel << "\n" << endl;
        
        my_strcpy(ziel+21, str2+32);
        cout << ziel << "\n" << endl;
        
        my_strcat(ziel, " ");
        my_strcat(ziel, str2);
        cout << ziel << "\n" << endl;
        
        tmp = my_strchr(ziel, ',');
        cout << (tmp == NULL?"NULL":tmp) << endl;
        tmp = my_strchr(ziel, 'S');
        cout << (tmp == NULL?"NULL":tmp) << "\n" << endl;
        
        cout << my_strcmp(str1, str2) << endl;
        
        return 0;
    }
    
    
    size_t my_strlen(const char *s)
    {
        const char *p = s; // Was genau passiert hier? Worauf zeigt p?      
        //p zeigt auf die gleiche Adresse wie s: auf einen String
        
        while(*++p); 
        
        return p-s;
    }
    
    
    char *my_strcpy(char *dest, const char *src) // Wofür ist der * bei my_strcpy?   my_strcpy gibt einen Zeiger auf ein char mit. Dieser zeigt auf einen String.
    {   
        char *temp = dest;
        while(*dest++ = *src++);
        
        return temp;
    }
    
    
    char *my_strcat(char *dest, const char *src)
    {
        char *temp = dest; 
        
        while(*dest)
            dest++;
        
        while(*dest++ = *src++);
        
        return temp; // Wieso nicht return dest? 
    }
    
    
    char *my_strchr(const char *s, char c)
    {
        while(*s)
        {
            if(*s==c)
                return const_cast<char*>(s); // s ist doch schon const char*? Wofür das Casten?    Dieser cast macht aus einem const char* ein char*
            s++;
        }
        return NULL;
    }
    
    
    int my_strcmp(const char *s1, const char *s2)
    {
        for(; *s1 == *s2; s1++, s2++)
            if(*s1 == '\0')
                return 0;
        return *s1 - *s2;
    }


Ich hoffe ich habe alle Fragen verständlich beantwortet und keine vergessen :D.

JRJ

Darkrel

Treue Seele

Beiträge: 143

Wohnort: Zürich

Beruf: Student ETH Zürich

  • Private Nachricht senden

3

19.06.2011, 23:31

1. Hat auch einen nutzen. Sieht man, wenn man das erste mal

int* p1, p2;

schreibt wenn man 2 Zeiger wollte ;)

4. i = p - a - 1 funktioniert weil dabei in sizeof(<Typ>) gerechnet wird. Die Frage war aber, wieso -1? Ganz einfach, *p++ ist ein post inkrement. Wenn die schleife unterbrochen wird, ist p schon einen index zu weit.

6. cout << str gibt im übrigen "ABC" zurück und nicht die Addresse von str aus, weil "operator <<" für char* (bzw. const char*) überladen ist.


Zum Rest gebe ich bei Lust und Laune noch meinen Senf dazu, aber der gigantische Text erschlägt mich ziemlich :p
:cursing:

AF1

Frischling

  • »AF1« ist der Autor dieses Themas
  • Private Nachricht senden

4

19.06.2011, 23:43

Danke für die Antworten.


Zu Punkt 10.

C-/C++-Quelltext

1
char *sa[] = {"eins\n", "zwei\n"}; // Wieso hier noch der *? Ist das char sa[][] bzw. char **sa?         JA

Wenn ich sa[][] schreibe und kompiliere, geht das nicht.

Zum Rest schreib ich morgen, muss mir das noch in Ruhe durchlesen. :thumbsup:

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

5

20.06.2011, 00:37

Wenn ich sa[][] schreibe und kompiliere, geht das nicht.

C-/C++-Quelltext

1
char sa[][] = {"eins\n", "zwei\n"};

Wäre nicht eindeutig da du keine Größenangabe gemacht hast (es könnte sowohl ein 1x2 Array als auch ein 2x1 Array sein). Es darf nur die erste Größenangabe freigelassen werden:

C-/C++-Quelltext

1
char sa[][6] = {"eins\n", "zwei\n"};

sollte gehen und ein 2x6 Array aus char machen, also ein Array aus 2 Arrays aus jeweils 6 char. Der Compiler braucht nämlich alle Größenangaben bis auf die erste um die Adresse eines Elementes des Arrays berechnen zu können.

Arrays sind keine Pointer. Arrays sind Arrays, sie sind lediglich implizit in einen Pointer auf das erste Element des Arrays umwandelbar. D.h. du kannst ein Array wie einen Pointer auf das erste Element benutzen, aber darum ist ein Array noch lange nicht das selbe wie ein Pointer auf das erste Element. Das wird auch sofort klar wenn du dir einfach mal anschaust was folgendes Programm ausgibt:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
#include <iostream>

int main()
{
  int a[10];
  int* b = a;
  std::cout << sizeof(a) << std::endl;
  std::cout << sizeof(b) << std::endl;
}


Ansonsten: Deklarationen liest man am Besten von "Innen" nach "Außen", also wie eine Zwiebel von der Mitte (Name des Objektes) weg:

C-/C++-Quelltext

1
2
3
4
5
6
char* a;        // Pointer auf char.
char c[10];     // Array aus 10 char.
char* b[5];     // Array aus 5 Pointern auf char.
char** d;       // Pointer auf Pointer auf char.
char e[4][10];  // Array aus 4 Arrays aus 10 char.
char* f[3][5];  // Array aus 3 Arrays aus 5 Pointern auf char.

Die "Zwiebelschalen" schauen so aus:

C-/C++-Quelltext

1
2
3
4
5
6
char (* a);            // Pointer auf char.
char (c [10]);          // Array aus 10 char.
char (* (b [5]));       // Array aus 5 Pointern auf char.
char (*(* d));         // Pointer auf Pointer auf char.
char ((e [4])[10]);     // Array aus 4 Arrays aus 10 char.
char (* ((f [3])[5]));  // Array aus 3 Arrays aus 5 Pointern auf char.

Dieser Beitrag wurde bereits 7 mal editiert, zuletzt von »dot« (20.06.2011, 00:52)


Darkrel

Treue Seele

Beiträge: 143

Wohnort: Zürich

Beruf: Student ETH Zürich

  • Private Nachricht senden

6

20.06.2011, 11:59

Wieso Zwiebeln und nicht Torten?
:cursing:

vorx

Frischling

  • Private Nachricht senden

7

20.06.2011, 14:30

1. Hat auch einen nutzen. Sieht man, wenn man das erste mal

int* p1, p2;

schreibt wenn man 2 Zeiger wollte ;)
Wenn ich mich nicht irre, sind das nicht 2 Zeiger.
p1 wäre ein Zeiger und p2 eine int variable.

EDIT: Sorry Text falsch aufgefasst ;)

so long
vorx

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

8

20.06.2011, 17:52

Wieso Zwiebeln und nicht Torten?

Oger sind nicht wie Torten, Oger sind wie Zwiebeln ;)
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Werbeanzeige