C Ist es möglich in C Arrays als Parameter zu übergeben?

Die Fi

Lt. Junior Grade
Registriert
Aug. 2005
Beiträge
298
Hi, ich möchte wissen, ob ich diese Code zum Ausführen bringe.
Code:
#include <stdio.h>

char ChngE(void);

void main()
{
	char txt[50];
		
	printf("Geben Sie eine Zeichenkette ein: ");
	scanf("%s", txt);
	printf("Der neue Text sieht Folgendermassen aus: %s\n", ChngE(txt));
}

char ChngE(char txt)
{
	char *pt;
	for (pt = txt; *pt; pt++)
		if ((*pt == 'e') | (*pt == 'E')) *pt = '-';
}

Ich möchte hier die Funktion ChngE() dazu benutzen die eingegeben Arrays zu bearbeiten und in der letzten printf verändert auszugeben.
Aber ich bekomme immer eine Fehlermeldung, dass es nicht möglich ist.

Ich vermute wie es bereits in der Überschrift deutlich klar wird, dass es an der Arrayübergabe als Parameter hängt, denn folgender Code funktioniert einwandfrei:

Code:
#include <stdio.h>

void main()
{
	char txt[50];
	char *pt;
		
	printf("Geben Sie eine Zeichenkette ein: ");
	scanf("%s", txt);
		for (pt = txt; *pt; pt++)
		if ((*pt == 'e') | (*pt == 'E')) *pt = '-';
	printf("Der neue Text sieht Folgendermassen aus: %s\n", txt);
}

Also geht es irgendwie die erste Möglichkeit zum laufen zum bringen wenn ja, was muss ich da verändern.

MfG DieFi
 
Zuletzt bearbeitet:
Das Array ist nichts weiter als ein Zeiger, der auf einen Speicherblock zeigt, der verschiedene char-Werte enthält. Wenn du ein Array übergibst, übergibst du somit einen Zeiger.
Das musst du ändern, dann sollte es laufen.
 
Kann man das also nicht irgnedwie doch umsetzen, vielleicht mit dem was CoolHandLuke sagte? Bei der Übergabe des Zeiger gleich mit eine Länge mit übergeben, sodass sich letzen Endes auch ein Array bildet?
 
Sollte man tunlichst machen. Die einzigen Arrays, bei denen man es nicht unbedingt tun muss, sind char-Arrays (Zeichenketten). Diese werden mit dem Null-Zeichen abgeschlossen. Andere Arrays haben kein solches definiertes Ende.
 
@Cobinja
Das ist mir per Definition bekannt, ich habe aber keine Ahnung, ob es wie im oberen Beispiel die Möglichkeit besteht das "txt" Array in die Funktion ChngE() zu übergeben dort verändern und am Ende in der printf() verändert auszugeben.
 
Das müsste folgendermassen klappen:

Da txt nur maximal 49 Zeichen aufnehmen kann (Das abschließende Null-Zeichen wird draufgerechnet), kannst du mit einer while-do-Schleife durch txt durchgehen, bis das 49. Zeichen oder ein Null-Zeichen erreicht wurde.
 
Das wird ja mit diesem Befehl ausgeführt:
Code:
	char *pt
        for (pt = txt; *pt; pt++)
		if ((*pt == 'e') | (*pt == 'E')) *pt = '-';

Der Pointer geht die ganze txt-Zeichen durch bis *pt (Also Abbruchbedienung) '0' (sprich Ende des Chararrays erreicht hat.)
 
Stimmt auch wieder.

Ich glaube, den Fehler gefunden zu haben:
Die Fi schrieb:
Code:
...

[COLOR=Red]char ChngE(char txt)[/COLOR]
{
    [COLOR=Red]char *pt;[/COLOR]
    for ([COLOR=Red]pt = txt[/COLOR]; *pt; pt++)
        if ((*pt == 'e') | (*pt == 'E')) *pt = '-';
}
Was fällt dir auf?
 
Hmm, stimmt wenn ich dies als Zeiger übergebe geht es.

Aber da stehlen sich mir 2 Fragen:
1. Ich dachte es wäre Möglich ein Array an einen Pointer zu übergeben, weil im Grunde nur die 1te Addresse des Arrays übergeben wird.
Und die 2te Frage ist, wieso kann ich dies nicht so ausführen
Code:
printf("Der neue Text sieht Folgendermassen aus: %s\n", ChngE(txt));
sondern muss die Funktion zuerst ausführen und dann erst übergeben.
Code:
ChngE(txt);
printf("Der neue Text sieht Folgendermassen aus: %s\n", txt);

?
 
ganz einfach: deine Methode liefert nichts zurück. Sie verändert das übergebene Array lediglich. Die Ausgabeanweisung will aber nen String an dieser Stelle.
 
0. Du hast 2 verschiedene Signaturen deiner Funktion ChngE in deinem Quelltext.

1. Deine Variable txt ist vom Typ char[], deine Funktion ChngE erwartet aber eine Variable vom Typ char als Parameter (und gibt auch nur char zurück). Du musst also auf jeden Fall die Signatur der Funktion ändern.

Code:
char[] ChngE(char[] txt)
oder
Code:
char* ChngE(char *txt)

2. Das dir eine return Anweisung in ChngE() fehlt wurde ja bereits erwähnt.

3. Du solltest dir vielleicht nochmal Gedanken über die Wahl der Funktionsnamen machen.

4. Du solltest das Array "ausnullen" bevor du es zum ersten Mal benutzt, sondern könnten unter Umständen noch irgendwelches altes Zeug darin sein, dass vorher mal auf den Stack geschoben wurde. (Hier vermutlich nicht, aber bei größeren Programmen kann das schnell mal passieren.)
 
Zuletzt bearbeitet:
Theoretisch schon, nämlich dann, wenn du das ganze Zeug auf den Heap haust und es selbst verwaltest.
Dafür brauchst du dann eine Adresse und den rest verwendest du bequem wie ein Array.
Aber das nur am Rande.
 
Nein, auch theoretisch ist ein Pointer ein Pointer und ein Array ein Array. Dass man nun einen Pointer als Array nutzen kann ist ne andere Sache. Pointer ist Pointer, und Array ist Array. Da gibts nix dran zu drehen, das ist Fakt.
 
XamBonX schrieb:
Nein, auch theoretisch ist ein Pointer ein Pointer und ein Array ein Array. Dass man nun einen Pointer als Array nutzen kann ist ne andere Sache. Pointer ist Pointer, und Array ist Array. Da gibts nix dran zu drehen, das ist Fakt.

XamBonX schrieb:

Die Quelle wählt leider auch nur ein unvollständiges Beispiel für den Vergleich 'Feld und Zeiger'.
Die Aussage 'Felder sind Zeiger und umgekehrt' ist natürlich theoretisch betrachtet abzulehnen, praktisch (zur Laufzeit in C/C++-übersetzten Anwendungen betrachtet) jedoch nicht falsch.

Das genannte Fall-Beispiel verleitet zusätzlich zu falschen Annahmen, beispielsweise, dass sizeof stets die Anzahl der Elemente eines Feldes zurückliefert, wenn der Parameter zur Übersetzungszeit ein Feld ist.

Code:
char *p = "hello";
char q[] = "hello";

Ausschlaggebend für die Korrektheit der nachfolgenden Ausführungen des Autors ist, WOMIT die Variablen initialisiert worden sind, und nicht nur, welchen Typs sie sind. "hello" als Stringliteral in der ersten Zeile wird zumeist im Nur-Lesen-Segment gespeichert, während "hello" in der zweiten Zeile im Lese-und-Schreib-Segment der Anwendung gespeichert wird. Dass auch das nur eine Annahme ist und es dem Linker überlassen bleibt, in welchen Segmenten er welche Symbole wie ablegt, wird nicht erwähnt. Selbst dann könnte der Loader des Betriebssystems noch die Flags der Segmente ignorieren und die Konstanten in einer nicht-schreib-geschützten Speicherseite ablegen, womit selbst ein char*-Zeiger, der auf ein Stringliteral gezeigt hat (das eigentlich in einem Nur-Lesen-Speicher-Segment liegen sollte), auf einen schreibbaren Bereich zeigen würde. In der Praxis ist dies jedoch mit an Sicherheit grenzender Wahrscheinlichkeit unmöglich, da Loader ein solches Programm eher nicht laden, als es mit diesen Bedingungen zu laden.


Der Autor weist dann einen impliziten const char* auf einen char* zu - nicht jedem Programmierer wird klar sein, warum das zu Semantikfehlern führen kann. Compiler weisen bei entsprechenden Warnstufen auch auf solche Fälle hin, die später zu Komplikationen führen kann.


In C/C++-übersetzten Anwendungen werden Felder im Speicher als zusammenhängende Sequenz von Werten abgelegt. Deshalb ist die Annahme, dass Felder Zeiger seien und umgekehrt unter C/C++ nicht komplett falsch. Die Aussage bezieht sich jedoch ausschließlich auf die (typisierte) Interpretation eines Zeigers unter C/C++ und ist somit als Allaussage (bezüglich aller Programmiersprachen) untauglich.

Folgende Ausführungen beziehen sich auf C/C++:

Sei F ein Feld mit n Elementen vom Typ T.
Gesamtgröße L des Feldes ist mit Hilfe der Anzahl der Elemente im Feld (n) bestimmbar:
L==sizeof(T)*n==sizeof(F)

Zudem gilt für alle ganzzahligen x: sizeof(F[x])==sizeof(T)

Nun ist für jeden typisierten Zeiger p vom Typ T an der ganzzahligen Stelle x definiert: p[x] == *(p+x) und damit auch sizeof(p[x]) == sizeof(*(p+x)) == sizeof(T)

Die Information über die gesamte Feldgröße (und damit die Anzahl der Elemente) geht bei der Übersetzung verloren. Selbst 'sizeof' wandelt beim Übersetzungsvorgang lediglich den inneren Ausdruck in eine Konstante um - sizeof steht damit nur zur Übersetzungs- und nicht zur Laufzeit zur Verfügung. Eine Feldgröße ist dann (zur Laufzeit) nur noch durch explizite Speicherung der Feldgröße (bzw. Elementanzahl) bei der Erzeugung oder durch implizite Annahmen bestimmbar (beispielsweise, dass bei C-Strings '\0' das Ende der Zeichenkette signalisiert).


Zurück zum Beispiel:
da hier der zugrundeliegende Datentyp 'char' ist und somit sizeof(q[0])==sizeof(p[0])==1 ist, kann ein weniger versierter Programmierer durchaus zu der Annahme gelangen, dass gilt: L==sizeof(F)==n und somit sizeof(F) die Anzahl der Elemente n von F bestimmt.

Hinzu kommt, dass für 3-stellige Zeichenketten plus Nullterminator bei 32-Bit-Compiler die Asserts jedoch folgendermaßen aussähen:

Code:
char *p = "abc";
char q[] = "abc";

...

assert(sizeof(p) == sizeof(char*)); 
assert(sizeof(q) == sizeof(char*));
assert(sizeof(q) == 4);

...was die These 'Felder sind Zeiger und umgekehrt' wiederum wieder nähren würde.

Somit widerlegt das Beispiel zwar die Allaussage 'Felder sind Zeiger und umgekehrt', lässt jedoch aus, warum und unter welchen Umständen dies zutrifft.
 
Arrays sind keine Zeiger. Arrays werden allerdings unter den meisten Umständen implizit durch die Array-To-Pointer Conversion in einen Zeiger auf ihr erstes Element umgewandelt. Ein Fall bei dem das nicht zutrifft, ist der sizeof-Operator.

Die Übergabe von Arrays an Funktionen ist nicht möglich (nur von Zeigern).

Eine Funktionsdeklaration
Code:
void foo( int a[10])
ist gleichbedeutend mit
Code:
void foo( int a[])
und
Code:
void foo( int* a)

Wobei die Array-Varianten implizit in die Pointer-Variante umgewandelt werden. (Nachzulesen im C-Standard unter 6.7.5.3/7) Bei Übergabe eines Arrays greift dann die Array-To-Pointer Conversion. (6.3.2.1/3)

Edit: Wobei ich mir hier mit den Variable Length Array Types nicht ganz sicher bin.

@XunnD:
Das hier aus deinem Beispiel vergleicht Äpfel mit Birnen:
Code:
assert(sizeof(q) == sizeof(char*));
Links steht ein Array, rechts ein Pointer.
 
Zuletzt bearbeitet:
7H3 N4C3R schrieb:
@XunnD:
Das hier aus deinem Beispiel vergleicht Äpfel mit Birnen:
Code:
assert(sizeof(q) == sizeof(char*));
Links steht ein Array, rechts ein Pointer.

Möchte nur betonen, dass das nicht mein Beispiel ist, sondern ich das als Analogie zur o.g. Quelle herangezogen habe und das auch verdeutlichen sollte, dass durch solche Annahmen durchaus Missverständnisse entstehen können.
 
Zurück
Oben