C++ Array übergeben und in for Schleife?

4 Antworten

In C ist ...

int zahlen[]

... kein Array, sndern ein Zeiger!

Das ist für Einsteiger oft etwas missverständlich.

Zu einem Arraytypen in C gehört IMMER auch die Größe dazu.

Wenn du also ...

int zahlen[5]

... schreibst, dann gehört die "5" zum Typen dazu, und es ist ein komplett anderer und inkompatibler Typ, als würdest du ...

int zahlen[42]

... schreiben.

Ein Zeiger hingegen wird ...

int * zahlen

... oder ...

int zahlen[]

... geschrieben, im letzten Falle also OHNE Größenangabe.

Implizit werden Arrays bei der Übergabe an Funktionen in Zeiger umgewandelt.

Innerhalb deiner Funktion ...

int getNumber(int zahlen[]);

... ist also nur ein int-Zeiger OHNE Größe sichtbar.

Randbemerkung: Deshalb können "Tricks" wie ...

size_t count = sizeof(zahlen) / sizeof(* zahlen);

... innerhalb der Funktion auch gar nicht funktionieren! Aber egal.

Der herkömmliche C-Weg wäre es jetzt, neben dem Arrayzeiger zusätzlich auch die Größe explizit an die Funktion zu übergeben:

int getNumber(int * numbers, size_t size) {
  int sum = 0;

  for (size_t i = 0; i < size; ++i) {
    sum += numbers[i];
  }

  return summe;
}

Aufgerufen wird so eine Funktion wie folgt:

int nums[] = {2, 4, 8}; // int nums[3]

int x = getNumber(nums, sizeof(nums) / sizeof(* nums));

Bei der Initialisierung des Arrays kann die Größenangabe entfallen, wie sie sich (wie oben) automatisch aus dem Kontext ergibt.

Und die Größe kannst du natürlich auch direkt als Wert an deine Funktion übergeben:

int nums[7];

// ... initialisiere nums

int x = getNumber(nums, 7);

Mit dem Unterschied zwischen Arrays und Zeigern haben oft sogar langjährige Programmierer Probleme, einfach weil sie es nie richtig gelernt haben.

So, und nun zu C++, da du in deiner Frage ja von C++ sprichst. Dort gibt es nämlich noch sehr viele weitere Möglichkeiten!

Das einfachste wäre, einfach ein auto-Template zu nutzen (ab C++17):

auto getNumbers(auto & nums) {
  int sum = 0;

  for (auto i : nums) {
    sum += i;
  }

  return sum;
}

Disclaimer am Rande: Der Einfachheit halber verzichte ich konsequent auf "const-Correctness" und vielen anderen Dingen, die C und vor allem C++ so bieten.

Die obige Funktion wäre normalerweise ein Einzeiler, wenn man es "richtig" machen wollte! Aber das ist jetzt nicht weiter wichtig.

Die Zweite Möglichkeit in C++ wäre ein explizites Array. Das funktioniert auch mit uralten C++-Versionen:

template <typename T, size_t N>
T getNumber(T (& nums)[N]) {
  // ... Rest wie im auto-Template ...
}

Dann gibt es noch die Möglichkeit mit Typetraits ...

#include <type_traits>

template <typename T>
T getNumber(T & nums) {
  int sum {};

  for (size_t i {}; i < ::std::extent<T>(); ++i) {
    sum += nums[i];
  }

  return sum;
}

Oder man nutzt von vornherein C++-Arrays, die ihre eigene Größe kennen, und nicht "vergessen" wie die C-Arraxs:

#include <algorithm>
#include <array>

int getNumber(auto & nums) {
  return ::std::accumulate(nums.begin(), nums.end(), 0);
}

// ...

::std::array<int, 7> numbers { 2, 3, 5, 7, 11, 13 };

int x = getNumber(numbers);

All das kann man auch nahezu beliebig kombinieren und es gibt noch eine ganze Reihe weiterer Möglichkeiten, die hier allerdings den Rahmen sprengen würden.

Wie gesagt, die obigen Beispiele haben alle einige Mängel, weil ich den Code absichtlich kurz und einfach halten wollte. In Produktivcode würde man "const", "noexcept", "[[nodiscard]]", uvm. Schlüsselwörter und Techniken zusätzlich nutzen.

Naja, lass dich von der Informationsflut nicht erschlagen! Soooo schlimm wie es aussieht ist das alles gar nicht. :)

Viel Erfolg noch! :)

Woher ich das weiß:Studium / Ausbildung
mjutu  15.10.2021, 10:51

Schöne Antwort. Eine Anmerkung:

Randbemerkung: Deshalb können "Tricks" wie ...
size_t count = sizeof(zahlen) / sizeof(* zahlen);
... innerhalb der Funktion auch gar nicht funktionieren!

Das kommt darauf an. Beispiel:

#include <stdio.h> 
void fun();
int zahlen[5] = {1,2,3,4,5};

void main(void) {
 fun();
}

void fun() {
 printf("%i\n", sizeof(zahlen) / sizeof(int));
}

Ausgabe: 5, wie erwartet. Wenn die Größe des Arrays zur Compile-Zeit bekannt ist, funktioniert sizeof(). Bei einem dynamisch allozierten Array natürlich nicht.

Wenn man hier dann von main and fun zahlen[] übergibt, ist klappt das Auslesen der Größe nicht mehr. Aber das Array ist mit "zahlen[]" auch gar nicht akkurat abgegeben, denn das Array ist ja als "int zahlen[5]" definiert worden. Wenn man es auch so übergibt, kann auch die Unterfunktion die Größe bestimmen.

Allerdings hat der FS inzwischen klargestellt, dass es um C++ geht. Dann ist das Herumgefuddel mit den historischen Methoden sowieso akademischer Natur.

0

FOR-Schleifen sehen in C anders aus:

for (int i = 0; i < n; i++)

Nun übergibst du lediglich Zahlen[], so dass der Compiler weiß, dass es ein Pointer auf ein Array ist. Er kann aber nicht wissen, wie groß das Array ist, also welchen Wert n hat. Wie möchtest du das bestimmen? sizeof() oder n explizit definieren und als zweiten Input mitübergeben?

In der Frage sprichst du von C, in den Tags steht C++. Um welche Sprache geht es genau?

Kannst du eine Kopie des Sourcecodes und der Fehlermeldung posten. Es nur ungefähr nachzuerzählen ist weniger hilfreich.

bitblt  14.10.2021, 21:50

Der Trick mit sizeof() wird innerhalb der Funktion nicht funktionieren können.

Bei C muss man zwangsweise die Größe als extra Argument mit übergeben. Da kommt man nicht drum herum. :)

1
mjutu  15.10.2021, 10:55
@bitblt

Siehe meinen Kommentar zu deinem Antwort: Es ist möglich mit sizeof() die Größe zu bestimmen, wenn man diese Information nicht vorher mit einem "Zahlen[]" explizit entfernt.

Dieses Gehuddel ist aber die Basis von Milliarden von Buffer-Überläufen, die Löcher in alle Betriebssysteme bohren. Es ist also besser, sich das von Anfang an konsequent abzugewöhnen.

0

for(int i : Zahlen[]) ist an sich nicht falsch, aber der weiß bereits, das "Zahlen" ein Array ist, deshalb kannst du die [] weg lassen

Dass das mit

for(int i : Zahlen[])

nicht funktioniert ist nicht im geringsten überaschend.

Selbst wenn es dir um C# und nicht um C ginge, Java ist ne ganz andere Geschichte.

Wenn, dann so:

int getNumber(int Zahlen[]){
    int n = sizeof(Zahlen)/sizeof(int);
    for(int i = 0; i < n; ++i) printf("%d\n", Zahlen[i]);
}

Wäre aber ziemlich "eklig", da man bei C eigentlich entweder die Länge mit übergibt oder einen bestimmten "Sonderwert" als EOA-(End of Array)-Marker benutzt... (Außerdem bin ich mir nicht 100% sicher, ob das so überhaupt funktionieren würde...)

Oder aber, falls es dir dann doch um C# gehen sollte:

int getNumber(int Zahlen[]){
    foreach(int zahl in Zahlen) System.Console.WriteLine(zahl);
}
bitblt  14.10.2021, 20:39

Das ist leider falsch! In C kann das so nicht funktionieren.

0
mjutu  15.10.2021, 10:53
@bitblt

Stimmt, das klappt nicht: Durch

int getNumber(int Zahlen[])

verliert Zahlen die Information, wie groß es ist und sizeof() kommt an diese Information nicht mehr heran.

0
Zahhak  15.10.2021, 12:50
@mjutu

Deswegen ja auch mein "nicht 100% sicher"... -.-

1
mjutu  15.10.2021, 16:39
@Zahhak

C erlaubt einem auf mannigfaltige Weise ein Loch ins eigenen Knie zu bohren. Hinterher kann man dann durch eines der Löcher hindurchschießen und verkünden: "Klappt!" :-)

2
Zahhak  15.10.2021, 16:45
@mjutu

Perfekte Metapher (oder Analogie?). ^^

1