Kurze Frage, Kurze Antwort

sheel

I love Asm
Hi

ja, auto versucht den passenden Typ zu erraten. Hat aber manchmal Ergebnisse, die man so nicht unbedingt erwartet, also etwas vorsichtig sein damit.

...

vector ist letztendlich eine Klasse mit Variablen und Funktionen in sich drin. Klassen können ein paar spezielle Funktionen haben, zB. einen Konstruktor: Eine Funktion, die den selben Namen wie die Klasse hat, und beim Erstellen von Instanzen der Klasse automatisch aufgerufen wird.
C++:
//vereinfacht geschrieben:

class vector
{
    ...

    vector(vector x)
    {
        //das wird in deiner zweiten Zeile aufgerufen, vom v2, und v1 wird als Parameter x übergeben
    }

    vector()
    {
        //es gibt auch einen Konstruktor ohne Parameter, der wird eben verwendet wenn nichts übergeben wird
    }

    ...

    int length()
    {
        return irgendwas;
    }

    ...
};

Was die Funktion beim echten vector dann macht ist, dass einfach der gesamte Inhalt kopiert wird.
v2 kopiert also die 5 double-Werte von v1 zu sich selbst rein.
 

coder111

Mitglied
Hallo,
dieses Programm soll einen eingegebenen sting in einen long umwandeln und die Quersumme berechnen. Das habe ich auch hinbekommen.
Unten stehender Code funktioniert.

C++:
const string str{"17462309"};
    long zahl=0,qs=0;
    for(char c: str){
        zahl= zahl * 10 +static_cast<long> (c-'0');
        qs+= static_cast<long> (c-'0');
    }
    cout << "Zahl = " << zahl << "\t\tQuersumme = " << qs << endl;


Wenn ich jetzt aber Zeile 4 etwas umändere (*= Operator benutzen), dann funktioniert das Programm nicht mehr. Als Ausgabe erscheint eine 0.

C++:
const string str{"17462309"};
    long zahl=0,qs=0;
    for(char c: str){
        zahl*= 10 +static_cast<long> (c-'0');
        qs+= static_cast<long> (c-'0');
    }
    cout << "Zahl = " << zahl << "\t\tQuersumme = " << qs << endl;
 

sheel

I love Asm
Naja, natürlich
C++:
zahl = zahl * 10 + c - '0';
//ist
zahl = ((zahl * 10) + c - '0');

zahl *= 10 + c - '0';
//ist
zahl = (zahl * (10 + c - '0'));
 

coder111

Mitglied
Ich habe mir gerade diese Aufgabe mehrmals durchgelesen aber ich verstehe nicht ganz, was ich da machen soll. Das fett markierte verstehe ich nicht.

Schreiben Sie ein Programm, das beliebig viele Zahlen im Bereich von -99 bis +100
(einschließlich) von der Standardeingabe liest. Der Zahlenbereich sei in 10 gleich große
Intervalle eingeteilt. Sobald eine Zahl außerhalb des Bereichs eingegeben wird, sei die
Eingabe beendet. Das Programm soll dann für jedes Intervall ausgeben, wie viele Zah-
len eingegeben worden sind.
Benutzen Sie für -99, +100 usw. Konstanten (const). Zur
Speicherung der Intervalle soll ein vector<int> verwendet werden.

Quelle: Der C++ Programmierer
 

sheel

I love Asm
Wie viel Zahlen sind zwischen 81 und 100, wieviel zwischen 61 und 80, wieviel zwischen 41 und 60 usw. ...
bis -99 bis -80
 

coder111

Mitglied
- Und falls, der Bereich über oder unterschritten wird, dann ist die Eingabe beendet? Also z.b. bei Eingabe 101?

- Und gilt das nur für den Zahlenbereich -99 bis +100? Oder sollen die Konstanten variabel gehalten werden?
 

coder111

Mitglied
Wozu bzw. wann löscht man den Tastaturpuffer?

C++:
cin.ignore(1000,'\n'); // Tastaturpuffer löschen


Und was ist der Unterschied zwische const und constexpr?
 
Zuletzt bearbeitet:

sheel

I love Asm
Wozu bzw. wann löscht man
Kommt auf dein Programm an. Wann willst du die Eingaben vor dem nächsten Enter ignorieren? (zumindest für dein Beispiel ist Entfer, und auch nur max. 1000 Byte)

...

Zu const und constexpr, das ist etwas umständlicher. Vielleicht ist noch nicht alles der folgenden Sachen bekannt, aber ich schreibs trotzdem einmal auf...

Zuerst einmal ein paar mögliche Anwendungsfälle und Eigenschaften von const.

a) Variablen machen, die (nach der Initialisierung) nicht mehr verändert werden können
C++:
int a = 1;
int b= a + 1;
a= 2;
Hier, noch ohne const, ist das alles in Ordnung. EIne int-Variable wird gemacht und bekommt Wert 1, wird zum Rechnen für was anderes verwendet und bekommt später noch den Wert 2. Wenn a jetzt "const int a = 1;" wäre, wäre Zeile 2 zwar in Ordnung (a wird ja nicht verändert, nur zum Rechnen verwendet), aber Zeile drei würde Compilerfehler erzeugen.
Mach zB. Sinn für
Code:
const double pi = 3.14159388;
, weil wenn man versehentlich Code schreibt der Pi ändert bekommt man einen Fehler... (aber auch vieles mehr, so fixe Zahlenkonstanten sind bei Weitem nicht der einzige Grund)

Aber: Das alles bisher bedeutet nicht, dass der Wert der Variable immer 1 ist.
C++:
int funktion1()
{
    int returnwert;
    cin >> returnwert;
    return returnwert;
}

...

const int a = funktion1();
Das ist genauso erlaubt. a bekommt seinen Wert durch eine Tastatureingabe, kann immer was anderes sein. const bedeutet "nur", dass es dann im restlichen Programm nicht mehr verändert werden kann.

Und eine weitere Falle
C++:
const int a = 1;

const int b;
b = 1;
a ist ok, b nicht. Es geht nicht darum, dass die "erste" Zuweisung erlaubt ist (schon deswegen, weil man bei Threads nicht immer ein "erstes" hat), sondern der Wert muss wirklich beim Anlegen der Variable schon reinkommen. Das "b=1" hier ist nicht erlaubt, und das Anlegen von b selber (const-Variable ohne Wert) liefert auch einen Fehler (nicht erlaubt weil es einfach keinen Sinn macht: Eine Variable, die nie einen Wert haben kann).

.
Außer, dass man vor Schlampigkeitsfehlern geschützt wird (wie bei pi oben, dass man sicher nicht ändern will), gibt es auch einen weiteren möglichen Vorteil: Geschwindigkeitsoptimierungen im Compiler EIn beliebter Teil davon:
C++:
int a = 1;
int b= a + 1;
a= 2;
Was in den Compiler reinprogrammiert ist kann in einfachen Situationen wie hier bestimmen, dass b 2 ist, und muss das Ausrechnen nicht ins Programm selber einbauen (damit spart man beim Ausführen vom Programm Zeit). Wenn zwischen Anlegen von a und b mehr Code ist kann der Compiler aber oft nicht sicher bestimmen, ob a noch immer 1 ist, und kann die Rechnung deshalb nicht einsparen. (Und auch kompliziertere Rechnungen sind ein Problem). (Btw., einen "perfekten" Compiler machen ist unmöglich, siehe Turings Halteproblem usw. Es gibt immer Codes, die einen Optimierer versagen lassen, egal wie gut er ist. Deshalb versucht man es auch gar nicht)
Wenn a jetzt const ist hilft das, weil sich der Optimierer sicher sein kann, dass sich a nicht ändert. Teilweise können dadurch dann eben noch schnellere Programme erzeugt werden.

.
Und noch ein weiteres Thema, falls Pointer schon geläufig sind: a auf 2 verändern kann über Umwege ja auch so gemacht werden:
C++:
int a = 1;
int *p = &a;
*p= 2;
Falls a const ist, gibts hier eine Reihe von Problemen: a zu ändern ist nämlich auch so nicht erlaubt, und der Compiler kann aber nicht in jedem Fall einen Fehler melden.
Warum nicht immer meldbar: Wieder mal das Halteproblem: Der Compiler kann bei großen/komplexen Programmen nicht immer mitverfolgen, ob p jetzt auf eine const-Variable zeigt oder nicht.
Warum nicht erlaubt Teil 1: Optimierungen, wieder. const heißt const. Die 2 technisch den Arbeitsspeicher schreiben kann schon funktionieren, aber wenn dann "b=a+1" kommt ist b eventuell trotzdem 2 und nicht 3. Und das war nur ein einfaches Beispiel, sich so gegen die Regeln wehren kann buchstäblich alle möglichen Auswirkungen haben. Falsches Verhalten wie hier, oder Abstürze, oder teilweise kanns wie erwartet funktionieren, je nach Gerät kanns auch explodieren... usw.usw. . EInfach nicht machen
Warum nicht erlaubt Teil 2: Bei "normalen" Computern zwar kein Problem, aber es gibt auch Geräte, wo const-Variablen in einem speziellen Speicherteil sind, in den wirklich nicht so einfach geschrieben werden kann.


....

b) Das waren normale const int, jetzt const Pointer nur kurz:
C++:
int a = 1;
int *p = &a;
Hier gibt es "drei" Sachen, die konst sein können:
Erstens, a:
C++:
const int a = 1;
int *p = &a;
Zweitens, die Adresse die in p gespeichert ist:
C++:
int a = 1;
const int *p = &a;
Drittens, das worauf p zeigt (nicht das Selbe wie Fall 1)
C++:
int a = 1;
int * const p = &a;
(oder auch mehrere, oder alle drei, const gleichzeitig)

Wenn a const ist, wie schon beschrieben, darf es nicht verändert werden (auch durch den Pointer nicht). Wenn p (Adresse) const ist kann es immer nur auf a zeigen, aber a kann beliebig geändert werden (egal ob durch p oder direkt).

Wenn p's Ziel const ist: p' Adresse kann verändert werden, es muss also nicht immer auf a zeigen. a kann auch verändert werden. Aber a kann nur direkt per "a=2" verändert werden, nicht durch p. (Bei dieser Variante gibts keine Probleme mit dem Optimierer usw. wenn man es umgehen will, a selber ist normal beschreibbar).

Was Ähnliches gilt auch für Referenzen, falls bekannt.

...

c) Funktionsparameter usw.
Ähnlich wie oben:
C++:
int plus1(const int x) { return x+1; }

int a = 1;
int b = plus1(a);
x in der Funktion darf nicht verändert werden, a außen selber aber schon.

Auch Returnwerte usw. ähnlich dazu

...

d) Noch etwas, was nicht ganz zu den vorigen Sachen passt
Funktionen von Klassen können const sein (die Funktion, keine Variable).
C++:
class abc
{
   int d;
    ...
   int f() const
   {
       d = 1;
    }
};
f ist hier const, also darf es keine Membervariablen der Klasse (also hier d) verändern. "d=1" => Fehler. d selber ist änderbar, nur f darf es nicht.

.
...
.

So, genug dazu.

constexpr ist noch strenger als const: Wirklich nur Sachen, die zur Compilezeit bestimmt werden können, dürfen das sein. (Was schafft der Compiler? Es gibt ja mehrere verschiedene Compiler ... es gibt gewisse Mindestanforderungen, die von allen Compilern erwartet werden)

Für einfache Variablen bedeutet das:
C++:
constepxr int a = 1; //ok
constepxr int b = 1+1; //ok, das schafft der Compiler
constepxr int c = a; //a ist auch constexpr, daher kann c auch bestimmt werden
constepxr int d = eineFunktionDieVonDerTastaturEinliest(); //nicht erlaubt
int e = eineFunktionDieVonDerTastaturEinliest(); //ausnahmsweise ein normales ist...
constepxr int f = e; //nicht erlaubt weil e nicht constexpr ist
//usw.
Es gibt auch constexpr-Funktionen: Sie haben ziemlich strenge Beschränkungen, was für Code drin sein darf, um den Returnwert auch zur Compilezeit bestimmbar zu machen. Den Wert solcher Funktionen kann man dann auch constexpr-Variablen zuweisen (anders als den Wert der Tastatur-Einlese-Funktion, die die Anforderungen für constexpr nicht erfüllen kann. Bei der constepxr dazuschreiben führt nur zu Compilerfehlern)

Die Details sidn deutlich komplizierter, aber hier egal.

Was das bringt:
a) Noch bessere Optimierungen (zumindest manchmal)
b) Es gibt in C++-Code manchmal Stellen, wo eigentlich nur fixe Werte (keine Variablen, keine Funktionsreturnwerte, nichts) eingetragen werden dürfen (zB. Größen von einfachen statischen Arrays, Literal-Templateparameter, usw.). constexpr-Variablen dürfen dort auch verwendet werden.