# 2 Anfänger Fragen: Array und Dev C++



## tobee (27. Juni 2006)

Hallo,

ich habe ein paar grundlegende Fragen zu C++. Speziell Dev C++.


```
int main (int argc, char *argv[])
{
int tage1[4] = { 1, 2, 3, 4 };
int tage2[3] = { 5, 6, 7 };
int tage[2] = { tage1, tage2 };
}
```

Meine Fragen:
1. Wieso macht Dev C++ immer diese Zeile mit rein: int argc, char *argv[].
2. Ist diese Zeile überhaupt richtig?: int tage[2] = { tage1, tage2 };

Schonmal Danke, Tobee


----------



## deepthroat (27. Juni 2006)

Hi.





			
				tobee hat gesagt.:
			
		

> Hallo,
> 
> ich habe ein paar grundlegende Fragen zu C++. Speziell Dev C++.
> 
> ...


So kann man auf die Parameter die dem Programm beim Start übergeben wurden zugreifen. Z.B. wenn dein Programm "test.exe" heißt, und du es von der Eingabeaufforderung mit "test.exe 1 2 hallo" aufrufst, dann ist in argc der Wert 4 (= Anzahl der Argumente im Array argv) gespeichert und argv hat den Wert { "test.exe", "1", "2", "hallo" }. 


			
				tobee hat gesagt.:
			
		

> 2. Ist diese Zeile überhaupt richtig?: int tage[2] = { tage1, tage2 };


Das kommt drauf an was du damit bezwecken willst. Willst du das tage Array mit den Adressen der Arrays tage1 und tage2 (implizit in einen int gecastet) initialisieren, dann ist es richtig. Der Compiler spuckt allerdings nicht ohne Grund die Warnung: "initialization makes integer from pointer without a cast" aus. Höchstwahrscheinlich ist es nicht ganz das was du möchtest.

Gruß


----------



## jokey2 (27. Juni 2006)

1. 
	
	
	



```
int main (int argc, char *argv[])
```
Das ist die Standard-Funktionsdefinition der C-Mainfunktion. Die Argumente können weggelassen werden, wenn man sie nicht braucht. Sie enthalten die Anzahl der Kommandozeilenargumente (argc) und das Array mit den Kommandozeilenargumenten (argv[]).
2. Ich denke, es müßte 

```
int* tage[2] = { tage1, tage2 };
```
heißen, da die Arrayelemente int-arrays sind. Normalerweise geht das aber so nicht, da die Array-Initialisierung afaik nur mit Konstanten funktioniert.


----------



## tobee (27. Juni 2006)

Danke an beide von euch.


```
int* tage[2] = { tage1, tage2 };
```
So hat es funktioniert. Aber was bewirkt denn der Stern hinter dem int?

Noch 2 Fragen:
1. Wie ermittle ich die Größe eines Arrays
2. Der Compiler hat mir gesagt der Syntax so sein müsste:

```
int main (int argc, char *argv[])
{
const char* tage1[4] = { 1, 2, 3, 4 };
const char* tage2[3] = { 5, 6, 7 };
const char** tage[2] = { tage1, tage2 };
}
```
.
Wieso denn dann 2 Sterne?

Tobee


----------



## deepthroat (27. Juni 2006)

jokey2 hat gesagt.:
			
		

> 1. Codetags
> 2. Ich denke, es müßte
> 
> ```
> ...


In C89 ist das tatsächlich nicht erlaubt - obwohl einige Compiler sich daran nicht unbedingt halten. C99 hebt diese Einschränkung jedoch auf. /edit: und in C++ ist es auch OK.

Gruß


----------



## deepthroat (27. Juni 2006)

Du solltest uns erstmal erklären was du damit überhaupt bezwecken willst. Was jokey2 gesagt hat bringt zwar den Compiler zum Schweigen, allerdings vermute ich das du keine Ahnung von Zeigern hast (da du nicht weißt was das Sternchen bedeutet) und das nicht das ist was du willst?! Ich kann mich natürlich auch irren.

Gruß


----------



## tobee (27. Juni 2006)

Sinn und Zweck von dem Programm gibt es nicht  
Ich mach gerade ein Tutorial in C++, aber das ist nicht so gut erklärt.
Zum Beispiel wird da nicht erklärt was es mit dem Sternchen aus sich hat.


Wie ermittle ich die Größe eines Arrays?


Tobee


----------



## deepthroat (27. Juni 2006)

Aha. Also wenn es keinen Sinn gibt dann bleibt ja nur die Syntax die man korrigieren kann.


			
				tobee hat gesagt.:
			
		

> ```
> int* tage[2] = { tage1, tage2 };
> ```
> So hat es funktioniert. Aber was bewirkt denn der Stern hinter dem int?


Dazu muß man wissen das Arrays im Grunde nur Zeiger sind. D.h. das sind Variablen die eine Adresse speichern. Diese Speicher-Adresse gibt an wo das Array anfängt - also wo das allererste Element das Arrays beginnt.

Das Sternchen bei der Variablendeklaration gibt an, das die Variable vom Typ ein Zeiger auf einen anderen Typ (in diesem Fall "int") ist. Dadurch das da auch noch eckige Klammern mit einer Konstanten stehen bedeutet das für die Variable tage, dass diese ein Array von 2 Elementen (Index 0 bis 1) vom Typ Zeiger auf int ist.

Bei Initialisierungen bzw. Zuweisungen sollten die Typen auf beiden Seiten des Gleichheitszeichens übereinstimmen. 

Da tage1 ein Array von int's ist, ist es auch gleichzeitig ein Zeiger auf int - also "int*". Dasselbe gilt für tage2. Wenn man tage1 bzw. tage2 als Element an das Array tage zuweisen will muß die Variable also ein Array von Elementen dieses Typs sein. Also wie es dort steht "int*".

Das gleiche gilt natürlich auch für die char* Arrays.



			
				tobee hat gesagt.:
			
		

> Noch 2 Fragen:
> 1. Wie ermittle ich die Größe eines Arrays


Für statische Arrays (so wie du sie jetzt definiert hast) kannst du den sizeof Operator verwenden:
	
	
	



```
int array[] = { 1, 2, 3, 4 };
int groesse = sizeof (array) / sizeof(array[0]);
```



			
				tobee hat gesagt.:
			
		

> 2. Der Compiler hat mir gesagt der Syntax so sein müsste:
> 
> ```
> int main (int argc, char *argv[])
> ...


Also erstmal stimmen bei der Initialisierung die Typen auf der rechten und linken Seite für die Arrays tage1 und tage2 nicht überein. Angeblich sind die Elemente dieser Arrays vom Typ "const char*", auf der rechten Seite hast du aber Integerwerte aufgelistet. 
	
	
	



```
const char* tage1[4] = { "eins", "zwei", "drei", "vier" };
```

Gruß


----------



## tobee (27. Juni 2006)

> Dazu muß man wissen das Arrays im Grunde nur Zeiger sind. D.h. das sind Variablen die eine Adresse speichern. Diese Speicher-Adresse gibt an wo das Array anfängt - also wo das allererste Element das Arrays beginnt.
> 
> Das Sternchen bei der Variablendeklaration gibt an, das die Variable vom Typ ein Zeiger auf einen anderen Typ (in diesem Fall "int") ist. Dadurch das da auch noch eckige Klammern mit einer Konstanten stehen bedeutet das für die Variable tage, dass diese ein Array von 2 Elementen (Index 0 bis 1) vom Typ Zeiger auf int ist.
> 
> ...



Erst mal Vielen Dank für deine ausführliche Antwort. Ich hab alles verstanden außer das mit dem Zeiger  . Der Zeiger verweist quasi auf eine Variable wo dann der Wert in dieser gespeichert ist?

// Edit:

```
char count(const char* a)
{
  return sizeof(a) / sizeof(a[0]);
}
```
Das ist meine Funktion wo ich die Array Größe ermittel.
Irgend etwas ist aber noch falsch?

Tobee


----------



## deepthroat (27. Juni 2006)

Ja, Zeiger sind erstmal ein etwas kompliziertes Konzept.

Zeiger sind Variablen die Adressen speichern. Punkt.

Mit dem Adressoperator & kann man sich die Adresse von Variablen besorgen.

Bsp:
	
	
	



```
int x = 5;

int* y = &x;
```
x ist eine Integervariable die mit dem Wert 5 initialisiert wurde. y ist eine Variable vom Typ Zeiger auf int. Mit dem &-Operator wurde die Adresse der Variablen bzw. genauer die Adresse an der der Wert der Variablen steht ermittelt; und dann an y zugewiesen.

y speichert jetzt also die Adresse an der der Wert der Variablen x steht.

Um den Wert der Variablen x zu verändern kann man den Zeiger *dereferenzieren*:
	
	
	



```
*y = 10;
```
Das Sternchen wird hier zum Dereferenzieren benutzt. Das bedeutet es wird nicht der Wert von y geändert, sondern da wo y hinzeigt wird der Wert 10 gespeichert. Die Variable x hat also jetzt den Wert 10, der Wert von y ist immer noch unverändert.

Nützlich werden die Zeiger wenn man dynamische Datentypen benutzt oder beim Funktionsaufruf wo Ausgabeparameter verwendet werden.

Gruß


----------



## deepthroat (27. Juni 2006)

tobee hat gesagt.:
			
		

> ```
> char count(const char* a)
> {
> return sizeof(a) / sizeof(a[0]);
> ...


Ich sagte ja bereits das du diese Methode nur bei statischen Arrays benutzen kannst.

Wenn du einen Zeiger an eine Funktion übergibst ist und bleibt das nur ein Zeiger. Dieser hat keine Struktur mehr und die Information die der Compiler von einem statischen Array hat sind nicht verhanden. Der Zeiger hat eine konstante Größe - auf einem 32bit System normalerweise 4 Byte. Da es ein Zeiger auf char ist, ist die Größe von a[0] immer 1 Byte. Das heißt die Funktion liefert immer 4 zurück.

Wenn du ein dynamisches Array benutzt (was erst zur Laufzeit erstellt wird), dann mußt du dir die Größe selbst merken, da der sizeof Operator nur zur Kompilierzeit verwendet werden kann.

Gruß


----------



## tobee (27. Juni 2006)

deepthroat hat gesagt.:
			
		

> Ja, Zeiger sind erstmal ein etwas kompliziertes Konzept.
> 
> Zeiger sind Variablen die Adressen speichern. Punkt.
> 
> ...



Also wäre dann x = 10 und y wäre immer noch 5. Oder?
Aber eins hab ich immer noch nicht verstanden.
Was ist der Sinn von Zeigern. Programm läuft schneller? Mehr Übersicht?    

Tobee


----------



## deepthroat (27. Juni 2006)

tobee hat gesagt.:
			
		

> Also wäre dann x = 10 und y wäre immer noch 5. Oder?


Nein. y speichert immer noch die Adresse von x. Man kann sich die Adresse ausgeben lassen:
	
	
	



```
printf("%p\n", y);
```



			
				tobee hat gesagt.:
			
		

> Aber eins hab ich immer noch nicht verstanden.
> Was ist der Sinn von Zeigern. Programm läuft schneller? Mehr Übersicht?


Einen Vorteil gibt's z.B. bei der Übergabe an Funktionen. Hat man eine Variable die viel Speicher belegt und übergibt diese als Parameter an eine Funktion, wird der Wert der Variablen kopiert wenn die Funktion aufgerufen wird. Das beansprucht Rechenzeit und auch Speicher - was nicht unbedingt notwendig ist. Übergibt man nur die Adresse der Variablen, hat man sich diesen Aufwand gespart. Hinzu kommt noch, das man den Wert der Variablen von der man die Adresse hat auch innerhalb der aufgerufenen Funktion ändern kann:
	
	
	



```
void func_a (int x) {
  x = 5;
}

void func_b (int* x) {
  *x = 5;
}

int main() {
  int z = 25;
  func_a(z);
  // z ist immer noch 25.

  func_b(&z);
  // z ist jetzt 5.
}
```
Gruß


----------



## tobee (27. Juni 2006)

deepthroat hat gesagt.:
			
		

> Nein. y speichert immer noch die Adresse von x. Man kann sich die Adresse ausgeben lassen:
> 
> 
> 
> ...



Das heißt.


> void func_b (int* x) {


Sagt der Funktion es kommt ein Zeiger als Parameter.



> *x = 5;


x wird dereferenziert.



> func_b(&z);


Erstellt einen Zeiger


Ist das so richtig?
Tobee


----------



## deepthroat (27. Juni 2006)

Ja, das ist so richtig.

Gruß


----------



## tobee (27. Juni 2006)

Danke. Da les ich wochenlang in C++ Bücher check nicht was Zeiger sind und du erklärst es mir in ~ 4 Stunden. Super


----------



## deepthroat (27. Juni 2006)

tobee hat gesagt.:
			
		

> Danke. Da les ich wochenlang in C++ Bücher check nicht was Zeiger sind und du erklärst es mir in ~ 4 Stunden. Super


Also bei mir hat es noch ein bisschen länger gedauert bis ich es wirklich verstanden hatte. Da hilft nur üben. 



			
				tobee hat gesagt.:
			
		

> Noch was:
> Ich habe ein Funktion die leider noch nicht funktioniert:
> 
> ```
> ...


Du übergibst da ein einzelnes Zeichen als Parameter an die Funktion. Da dürfte sich der Compiler ziemlich beschweren wenn du den Index-Operator (die eckigen Klammern) anwenden willst.

Du kannst den sizeof Operator wirklich nur verwenden um die Größe eines Arrays zu bestimmen wenn du direkt eine (statische) Array-Variable vorliegen hast:
	
	
	



```
int x[] = { 1, 2, 3 };

int count = sizeof(x) / sizeof(x[0]);
```
Der Compiler hat in dem Fall die Information darüber das x eine Array-Variable ist, wie groß x ist und wie groß jedes einzelne Element von x ist. Wenn du x an eine Funktion als Zeiger übergibst, ist diese Information nicht mehr vorhanden. Die Äquivalenz gilt eben nur in eine Richtung: ein Array ist ein Zeiger, aber nicht jeder Zeiger ist automatisch auch ein Array.

Um Arrays in Funktionen verarbeiten zu können, muss immer (wie z.B. der main Funktion selbst) die Anzahl der Elemente bzw. die Größe des Arrays als Parameter übergeben werden. Oder man benutzt ein speziellen Wert um das Ende des Arrays zu markieren - wie z.B. bei Strings, da markiert ein NUL Zeichen das Ende eines Strings (ist nichts anderes als ein char-Array).

Du könntest count höchstens so schreiben:
	
	
	



```
int count(int sz, char arr[]) {
  return sz / sizeof(arr[0]);
}

char array[] = { 'a', 'b', 'c' };
int size = count (sizeof(array), array);
```

Du könntest allerdings auch ein Makro verwenden:
	
	
	



```
#define COUNT(x) (sizeof(x) / sizeof(x[0]))

int size = COUNT(array);
```
Das Makro wird expandiert bevor der C/C++ Compiler den Code verarbeitet und es ist im Grunde dasselbe wenn du gleich die sizeof Berechnung hinschreibst.

Gruß


----------



## tobee (27. Juni 2006)

Ok, eine "dumme" Frage habe ich noch Lager 


```
int count(int sz, char *arr[])
{
  return sz / sizeof(arr[0]);
}
```

Würde das hier einen Unterschied machen, wie zu dem hier:

```
int count(int sz, char arr[])
{
  return sz / sizeof(arr[0]);
}
```

Die Funktion erwartet ja einen Zeiger?
Und wenn keiner kommt?


Tobee


----------



## deepthroat (27. Juni 2006)

Ok. Also erstmal ist ja der Parameter arr bei den Funktionen von einem unterschiedlichen Typ. Das erste ist ein Array von Zeigern auf char und das zweite nur ein Array von char.

Da müssen dann wieder die Typen beim Aufruf passen. Das sollte der Compiler dann auch bemängeln. Einen Unterschied macht es insofern, das die Elemente der Arrays eine andere Größe haben. Ein char ist immer 1 Byte groß und ein Zeiger ist bei 32bit Systemen meist 4 Byte groß. 

Übergeben wird allerdings immer ein Zeiger. Wird ein falscher Typ übergeben der nicht mit dem Typ des Parameters kompatibel ist stimmt die Berechnung nicht mehr. Übergibt man der ersten Funktion statt des erwarteten char*-Arrays z.B. ein char-Array ist die Berechnung natürlich falsch.

C ist da sehr nachlässig und gibt dem Programmierer sehr viel Freiheiten. Deshalb sollte man immer alle Warnungsmeldungen des Compilers anzeigen lassen und dann die Ursachen beseitigen. /edit: C++ ist da übrigens sehr viel strenger und dieser Code würde nicht akzeptiert werden.

Gruß


----------



## tobee (27. Juni 2006)

Ich habe gerade ein kleines Programm geschrieben und ein Kollege hat gesagt wenn ich den Bildschirm "leeren" möchte muss ich nur cls eingeben.
Das funktioniert aber leider nicht.
Ich hab es schon so

```
cls;
```
und so

```
cls();
```
probiert. Oder war das eine falsche Information?

Tobee


----------



## deepthroat (28. Juni 2006)

Naja, ganz falsch war es nicht. Unter DOS/Windows gibt es einen DOS Befehl der cls heißt. Der muss allerdings auch von DOS ausgeführt werden. DOS Befehle kannst du in C mit der system Funktion aufrufen:
	
	
	



```
system("cls");
```
Es gibt auch Funktionen in unterschiedlichen Bibliotheken (Borland z.B.) dafür aber dies sind keine Standardfunktionen und nicht immer verfügbar.

Gruß


----------

