Wozu sind es Zeiger?

moinsen

Ich habe das Prinzip von Zeiger noch nicht ganz verstanden. Hier ein Beispiel

#ifndef STASSID
#define STASSID "your-ssid"
#define STAPSK  "your-password"
#endif

const char* ssid = STASSID;
const char* password = STAPSK;

wozu muss ich denn einen Zeiger auf der SSID und dem Passwort haben. ich kann es doch auch einfach Direkt mit const char definieren.
Mfg

Ja, kannst du!

Zeiger und Array Zugriffe sind Äquivalent.

Aehm, Momentchen:

const char *c="hallo";
const char c="hallo";
const char c="hallo";

die ersten 2 sind gleich, der dritte beißt dich ins Wadl.

const char[] c=“hallo”;

const char c[]="hallo";

hier drei gültige Varianten

using CharArray = const char[20];

const char *a   = "hallo";
const char  b[] = "hallo";
CharArray   c   = "hallo";

Hi

gilt das denn nur für Arrays? wenn nein wozu brauch in dann Zeiger ?

Mfg

gilt das denn nur für Arrays?

Dahinter steckt eine Vorstellung.
Und diese ist vermutlich falsch/irrig.

Darum kommt mir die Frage auch etwas absurd vor.

wozu brauch in dann Zeiger ?

Zeiger zeigen in den Speicher.
Das musst du entscheiden, ob du Zeiger brauchst.

Außerdem:

Zeiger und Array Zugriffe sind Äquivalent.

Ein Array hat eine feste Adresse. Ein Zeiger kann auf ein beliebiges Element im Array zeigen, kann vor und zurück bewegt werden...

Ein Array hat eine feste Adresse.

?

Hmmm ..
Ein Zeiger zeigt auch immer nur auf feste Adressen...
( ... aber ich weiß, glaube ich, was du meinst ...)

const char  *c {"hallo"};

void setup() 
{
  Serial.begin(9600);
  Serial.println(0[c]);   // sagt h
  Serial.println(1[c]);   // sagt a
  Serial.println(c[2]);   // sagt l
  Serial.println(*(c+3)); // sagt l
  Serial.println(*(c+4)); // sagt o
}

void loop() 
{

}

Eurovision:
wozu brauch in dann Zeiger ?

Ein Beispiel ist die Verwendung als Funktionsparameter. Ein Beispiel:

void setup() {
  Serial.begin(9600);
  Serial.println("Anfang");
}

byte addiere1(byte wert) {
  wert++;
  return wert;
}
void addiere2(byte *wert1, byte *wert2) {
  *wert1 += 1;
  *wert2 = *wert1 * 5;
}

void loop()
{
  static byte j = 0;
  static byte k = 0;
  static byte m = 0;
  if (j < 10) {
    j++;
    k++;
    byte w = addiere1(j);
    Serial.print("j = ");
    Serial.print(j);
    Serial.print("\tFunktion = ");
    Serial.print(w);
    Serial.print("\tj = ");
    Serial.println(j);

    Serial.print("k = ");
    Serial.print(k);
    addiere2(&k, &m);
    Serial.print("\t\t\tk = ");
    Serial.print(k);
    Serial.print("\tm = ");
    Serial.print(m);
    Serial.println();
    Serial.println();
  }
}

Die Funktion addiere1 bekommt einen Parameter übergeben und gibt den berechneten Wert zurück. Die Parametervariable bleibt dabei unverändert, weil die Funktion eine Variablenkopie verwendet. Das ist der “normale” Ablauf.

Mit Zeigern kann man nun die Parametervariable in der Funktion verändern. Die Funktion legt keine Kopie an, sondern arbeitet mit der Parametervariablen selbst. Bei addiere2 kann man das sehen.

[sup]Anfang
j = 1	Funktion = 2	j = 1
k = 1			k = 2	m = 10

j = 2	Funktion = 3	j = 2
k = 3			k = 4	m = 20

j = 3	Funktion = 4	j = 3
k = 5			k = 6	m = 30

j = 4	Funktion = 5	j = 4
k = 7			k = 8	m = 40

j = 5	Funktion = 6	j = 5
k = 9			k = 10	m = 50

j = 6	Funktion = 7	j = 6
k = 11			k = 12	m = 60

j = 7	Funktion = 8	j = 7
k = 13			k = 14	m = 70

j = 8	Funktion = 9	j = 8
k = 15			k = 16	m = 80

j = 9	Funktion = 10	j = 9
k = 17			k = 18	m = 90

j = 10	Funktion = 11	j = 10
k = 19			k = 20	m = 100

[/sup]

Von

void addiere2(byte *wert1, byte *wert2) {
  *wert1 += 1;
  *wert2 = *wert1 * 5;
}

möchte ich dringendst abraten!

Das ist in C vielleicht Sinn behaftet
Denn das kennt keine "Referenzen".

In C++ macht man das besser so:

void addiere3(byte &wert1, byte &wert2) {
  wert1 += 1;
  wert2 = wert1 * 5;
}

Wenn man denn wirklich auf Seiteneffekte setzt.

Aufruf, dann so:

   //addiere2(&k, &m);
    addiere3(k, m);

Wie auch immer...
In C++ kann man recht gut auf Zeiger verzichten.
Nicht immer, aber gut und gerne.

Bei richtigen Computern (mit RAM - Speicher), wo new / delete Sinn macht, stellt sich die Frage nach Zeigern gar nicht. Da fragt man höchstens, ob man nackte Zeiger oder besser smart pointer verwendet.

Zu C - Zeiten (und in älteren C++ - Versionen) gab es übrigens kein Using, sondern nur typedef.

Aber an using könnt/sollte ich mich wohl gewöhnen. Danke Combie.

using CharArray_u = const char[];
typedef const char CharArray_t[]; 

CharArray_u a = "Hello World!";
CharArray_t b = "Hello Again";

void setup() {
  Serial.begin(9600);
}

void loop() {
  Serial.println(a);
  Serial.println(b);
  delay(1000);
}

Aber an using könnt/sollte ich mich wohl gewöhnen. Danke Combie.

Gerne doch.
Ich finde using viel angenehmer.

Mit typedef hatte ich immer schon "intutive" Probleme.
Dessen Syntax ist mir quer.

using CharArray_u = const char;
ist gleichewertig zu
using CharArray_u = const char*;

Ich neige eher zu einer solchen Definition

using CharArray_u = const char[22];

Das macht den Type auch eher für sizeof() zugänglich

Hallo,

vielleicht hilft dir der Thread weiter. Zeiger Intermezzo

Leider vergisst man einiges wieder wenn es man es nicht ständig benötigt. :wink:

Genau dafür habe ich die Bsp. hinterlegt, sozusagen als Nachschlagewerk für mich und andere.

combie:
Ich finde using viel angenehmer.

using CharArray_u = const char;

Gut zu wissen, daß C++ endlich die Vorzüge von Pascal entdeckt :-]
type CharArray = array of char;

type CharArray = array of char;

using CharArray_u = const char;
Definiert kein Array, sondern einen Zeiger auf const char. ← korrigiert
Definiert kein Array, sondern einen nicht kompletten Datentype
Genau darum mag ich das nicht.
Ist gegen die/meine Intuition

using CharArray_u = const char*;
Dieses macht viel klarer, was gemeint ist.

Oder die bevorzugte Bevorzugung: Feste Array Größe.

using CharArray_u = const char[22];

combie:

using CharArray_u = const char;
Definiert kein Array, sondern einen Zeiger auf const char.

Dann versuche mal

CharArray_u a = "Hello World";
a = "sonstwas";
a++;

was bei einem Zeiger erlaubt ist, nicht aber bei einem Array. Nur an Pointer-Arithmetik kann man in C/C++ Pointer und Arrays unterscheiden, nicht an einer Indizierung.

Das "const" ist mir in diesem Zusammenhang nicht klar, in C gibt es 3 verschiedene Bedeutungen für const.

Ja, es ist nicht ganz richtig mit dem Zeiger.
Das muss ich zugeben.
Da hast du voll wahr!
.Danke für die Korrektur.

Aber CharArray_u ist auch kein Array, kein kompletter Datentype.
Und das ist das wirklich unangenehme an dem

using CharArray_u = const char;
Dingen.
Man kann es eigentlich für fast nix verwenden.

Darum sachte ich eben auch schon:

using CharArray_u = const char*;
using CharArray_u = const char[22];
Das sind die beiden guten Varianten.
Feine, nutzbare, Datentypen.

Und diese ist die ganz unglückliche:

using CharArray_u = const char;

Ich vermute, dass mein Irrtum u.a. darin begründet ist, dass ich das Ding nicht leiden kann, ablehne und für mein Leben quasi ausgeblendet habe.

Nachweis: Serial.println(sizeof(CharArray_u));

Ein Feature von C ist die Automatik für Array-Dimensionierung, die sich aus der Anzahl Elemente ergibt, die bei der Definition der Variablen angegeben werden. Ob da bei Strings auch ein Null-Byte angehängt und mitgezählt wird, entzieht sich meiner Kenntnis - sollte aber vernünftigerweise so sein.

sizeof(type) ist nicht immer hilfreich, wie Du selbst bemerkt hast. In Pascal (Delphi OPL) ist array ein dynamisches Array, dessen Größe zur Laufzeit wechseln kann. Die Implementierung ist sehr anwenderfreundlich und tricky, damit möchte ich C Programmierer jetzt nicht überfordern.

Ein Feature von C ist die Automatik für Array-Dimensionierung, die sich aus der Anzahl Elemente ergibt, die bei der Definition der Variablen angegeben werden. Ob da bei Strings auch ein Null-Byte angehängt und mitgezählt wird, entzieht sich meiner Kenntnis - sollte aber vernünftigerweise so sein.

Ist so!
Bei C-Strings zeigt strlen() immer min 1 char weniger als sizeof() zu dem Array sagt.
(sonst Problem)

Auch C++ kennt dynamische Arrays.
Aber nicht auf unseren AVR Zwergen.

sizeof(type) ist nicht immer hilfreich,

Ein “inkompletter Type”, dessen Größe ich nicht mit sizeof() ermitteln kann ist kein Type.
Für mich ist das ein Nogo.
Denn z.B. bei Buffern usw. interessiert mich oft nicht, wie lang der String darin ist, sondern wieviel da rein passt.

Ok, ok Auch Template-klassen/funktionen sind “inkomplete Dinge” solange sie noch nicht spezialisiert sind.
Aber da kann man das using schön nutzen, um eben aus den “inkompletten Templates” vollwertige Typen zu spezialisieren/bilden.

Hier ein Beispiel für die Unbrauchbarkeit solcher inkompletter Typen.

using IntArray = const int[]; // inkomplete
//using IntArray = const int[4]; // komplete

IntArray a {4,7,1,1};

void tuwas(IntArray &a)
{
  for(int i:a)  Serial.println(i);
}



void setup() 
{
 Serial.begin(9600);
 Serial.println("Start");
 tuwas(a);
}

void loop() 
{

}

Erst:

void tuwas(auto &a) // ab C++17
{
  for(int i:a)  Serial.println(i);
 // for(decltype(a[0]) i:a)  Serial.println(i);
 // for(auto i:a)  Serial.println(i);
}

Verschafft Linderung

Alternativ

template<typename T> void tuwas(T &a)
{
  for(int i:a)  Serial.println(i);
}

Da muss man schon aufpassen, dass man sich so keinen Code Bloat einfängt.

using IntArray =  int[];

struct test
{
  int bli;
  byte bla;
  IntArray blub; // warning: ISO C++ forbids flexible array member 'blub'
};

In C ist sowas durchaus erlaubt, und auch gängige(?) Praxis.

struct test
{
  int bli;
  int bla;
  int blub[];
};

Aber dann verbunden mit malloc() und seinen Freunden.


Also, für mich ist das etwas absurd, einen inkompletten Typen zu kreieren und dann zu sagen: sizeof() wäre nicht immer hilfreich.
Das “schmeckt” mir irgendwie nicht.
Aber, was mir nicht schmeckt, ist ja nicht das Maß aller Dinge.

Irgendwie erinnert mich das an die alte Frage:

Was ist das?
Je mehr es trocknet, desto nasser wird es.

Weißt du es?

Ein Handtuch