Array wird nicht kleiner, obwohl in Funktion definiert

OP #4750442
Ich experimantiere gerade mit den 1Wire Sensoren DS18x20 rum.

Hier ein Auszug aus dem Programm (vieles aus dem Forum zusammengeklaut 
;) ):

/**
* Liest die Adressen alle Sensoren aus und gibt sie zurück
*/
void scan_bus(uint8_t addresses[MAX_SENSORS][8]) {

    uint8_t id[8], diff;
    uint8_t i = 0, z = 0;
    char s[10];

    for (diff = SEARCH_FIRST; diff != LAST_DEVICE;) {
        diff = w1_rom_search(diff, id);

        for (z = 0; z < 8; z++) {
            addresses[i][z] = id[z];
  }
}

void read_temp() {
    uint8_t addresses[MAX_SENSORS][8];

    scan_bus(addresses);

  for (z = 0; z < MAX_SENSORS; z++) {
    if (!addresses[z][0]) {
      break;
    }
                // fürs debugging mal ausgeben:
    sprintf(s, "Sensor %d\t", z);
    uart_puts(s);
    for (uint8_t x = 0; x < 8; x++) {
      sprintf(s, "%02X:", addresses[z][x]);
      uart_puts(s);
    }
    uart_puts("\n\r");
  }


}

int main {
    while(1) {
        read_temp();
         _delay_ms(5000);
    }
}

Das tut auch erst mal ABER
wenn ich am Bus einen von zwei Sensoren ziehe, steht in addresses[1] 
plötzlich der Wert des ersten, erwarten würde ich aber 
00:00:00:00:00:00:00:00.
Stecke ich den wieder rein, dann steht in addresses[1] wieder der 
richtige Wert. Ziehe ich ihn wieder raus, na Ihr wisst schon ....

Zweite Frage:
Aus der Funktion w1_rom_search bekommme ich über uint8_t id[8] die 
HardwareAdresse. Die ich dann über so eine komische for-Schleife an 
addresses zuweise. Geht das nicht auch eleganter?
Ich denke an Pointer, habe ich aber nicht hin bekommen.
Ich kann mir kaum vorstellen, dass in adresses[1][] überhaupt 
irgendetwas anderes als zufällige Werte drin stehen.
In scan_bus() wird i nicht erhöht, ist also immer 0, daher ändert sich 
immer nur adresses[0][].
Wozu char s[10] in scan_bus() deklariert wird bleibt auch ein Rätsel.

Generell ist es ja eher so, dass so ein Scan einmalig beim Start der 
Hardware gemacht wird. Ob das "plug-and-play" fähig ist müsste man 
erstmal prüfen.
Gast
Johannes A. schrieb:
> wenn ich am Bus einen von zwei Sensoren ziehe, steht in addresses[1]
> plötzlich der Wert des ersten, erwarten würde ich aber
> 00:00:00:00:00:00:00:00.

warum erwartest du das? Wer soll dort die 00:00 ... reinschreiben?

Du musst dir vermutlich selber merken, wie viele Device im Array gueltig 
sind.
OP
Konnte ich mir nicht vorstellen, habs trotzdem getestet.
Nein ein Reset ist nicht nötig. Ein Bus-Reset setzt keine Variablen 
zurück und wo nix ist, kannn nix antworten. Das ist ein Softwareproblem!
Ich habe ein Array das nicht wieder auf Null oder leer gesetzt wird, 
obwohl die Funktion ja verlassen wird.
OP
Habe gerade die Sensoren vertauscht, im Sinne von welcher gezogen wird 
und welcher drinn bleibt.
Da die Dinge in Reihenfolge der Adressen abgefragt werden und antworten, 
ist es je nach Adresse so, das entweder zwei mal die gleiche ausgegeben 
wird, (wenn vorher der Einzelne auf [1] stand) oder sich gar nichts 
ändert. Debugausgaben zeigen an, das wirklich vernüftige Daten 
ausgelesen werden. Also nix mit fehlendem Bus-Reset oder so.
Gast
Johannes A. schrieb:
> Da die Dinge in Reihenfolge der Adressen abgefragt werden und antworten,
> ist es je nach Adresse so, das entweder zwei mal die gleiche ausgegeben
> wird, (wenn vorher der Einzelne auf [1] stand) oder sich gar nichts
> ändert.

die 2. wir nicht ausgegeben, die schleife wird woher beeendet. Sie steht 
nur noch drin.

mache doch vorher man alles leer (memset)
OP
Das würde bedeuten, das das
    uint8_t addresses[MAX_SENSORS][8];
in read_temp() nur einmal im Leben des gesamten Programms ausgeführt und 
der Stack nicht aufgeräumt wird. Ist aber nicht mein Verständnis.
Sollte nicht bei jedem read_temp() die Variable neu erzeugt werden. Ich 
habe sich ja nicht static oder global gemacht.
Gast
mache doch einfach mal
1
void scan_bus(uint8_t addresses[MAX_SENSORS][8]) {
2

3
    uint8_t id[8], diff;
4
    uint8_t i = 0, z = 0;
5
    char s[10];
6

7
    memset(addresses, 0, sizeof( addresses) );
8
    for (diff = SEARCH_FIRST; diff != LAST_DEVICE;) {
9
        diff = w1_rom_search(diff, id);
10

11
        for (z = 0; z < 8; z++) {
12
            addresses[i][z] = id[z];
13
  }
14
}

oder lass scan_bus als return die anzahl der device ausgeben.
Machs halt gleich richtig, und lasse dir von scan_bus() die Anzahl der 
gefundenen Devices zurückgeben
1
int scan_bus(uint8_t addresses[MAX_SENSORS][8]) 
2
{
3
  (...)
4
    i++;
5
  (...)
6

7
  return i;
8
}
9

10

11
void read_temp() {
12
  uint8_t addresses[MAX_SENSORS][8];
13
  int devices;
14

15
  devices = scan_bus(addresses);
16

17
  for (z = 0; z < devices; z++) {
18
   (...)
19
}

Dann kannst du auch
1
 if (!addresses[z][0]) {

rausschmeissen, ist ja eh nicht zuverlässig, wenn das oberste byte der 
Adresse mal zufällig 0 sein sollte...


Update:
Peter II schrieb:
> oder lass scan_bus als return die anzahl der device ausgeben.

Wenn sich 2 schon so einig sind... ;-)
OP
@Peter II

Dein Vorschlag tut nicht. Nix wird genullt. Bekomme aber eine 
Warnmeldung vom Compiler:
warning: argument to ‘sizeof’ in ‘memset’ call is the same expression as 
the destination; did you mean to dereference it? 
[-Wsizeof-pointer-memaccess]
memset(addresses, 0, sizeof( addresses) );

@Peter II &  @(easylife)

Natürlich kann ich das so lösen, wie Ihr beide vorgeschlagen, das löst 
aber nicht mein Verstädnisproblem.
Dein Verständnisproblem kann man natürlich auch nur ahnen.
Ich denke, du gehst davon aus, dass addresses[][] irgendwo genullt 
werden würde.
Das passiert aber im günstigsten Fall nur bei Programmstart (wovon man 
übrigens nicht ausgehen sollte).
scan_bus() überschreibt einfach nur Werte im Array, das in read_temp() 
deklariert wurde.
Beim erneuten Aufruf von scan_bus() bleiben die alten Werte natürlich 
erhalten, weil scan_bus ja weniger Adressen ins Array schreibt (bei dir 
momentan 1, d.h. die 2. Adresse bleibt erhalten).
OP
habe gerade folgendes gemacht:

in read_temp()

uart_puts("Init addresses[MAX_SENSORS][8] ...\t");
uint8_t addresses[MAX_SENSORS][8];
uart_puts("Init addresses[MAX_SENSORS][8] fertig\n\r");

Es wird wirklich uint8_t addresses[MAX_SENSORS][8]; jede mal neu 
ausgeführt. Offensichtlich werden aber Arrays im Ggs. zu anderen 
Variablen NICHT aufgeräumt bzw. ausgenullt. Bei int usw. soll das ja 
angeblich gemacht werden. C ist ne komische Sprache, oder ich hab was 
nicht verstanden.
Gast
Johannes A. schrieb:
> Es wird wirklich uint8_t addresses[MAX_SENSORS][8]; jede mal neu
> ausgeführt.

das ist überhaupt kein Befehl der ausgeführt werden kann.

Es ist eine Anweisung auf dem Stack platz für ein paar Byte 
einzurichten. Dabei wird überhaupt nicht genullt.

Dann müsste man schon
1
uint8_t addresses[MAX_SENSORS][8] = {0};

schreiben.
Johannes A. schrieb:
> C ist ne komische Sprache, oder ich hab was
> nicht verstanden.

letzteres.
1
uint8_t addresses[MAX_SENSORS][8];

wird nicht ausgeführt, sondern reserviert Speicher.

Der Aufruf scan_bus(addresses) übergibt dann einen Pointer auf diesen 
Speicherbereich an scan_bus();

In C wird speicher nie automatisch initialisiert. Auch andere Variablen 
nicht.
Manche Compiler machen das zwar, davon darf man aber nicht ausgehen.

Update: ich halte mich jetzt hier raus, das ist ja beängstigend, wie 
Peter und ich im Mintentakt das gleiche sagen... ;-)
Gast
Joe F. schrieb:
> In C wird speicher nie automatisch initialisiert. Auch andere Variablen
> nicht.
doch, nur nicht bei lokalen Variablen. Globale werden immer 
initialisiert.

> Manche Compiler machen das zwar, davon darf man aber nicht ausgehen.
es ist genau definiert, was initialisiert werden muss und was nicht.
OP
uint8_t addresses[MAX_SENSORS][8] = {{0}};
hat das Problem gelöst.
Scheinbar habe ich das falsch verstanden.

Allerdings:

void test_var() {
  uint8_t z;
  char s[10];
  z++;
  sprintf(s, "%d\n\r", z);
  uart_puts(s);

}


von main periodisch aufgerufen, bringt immer 1
schreibe ich static uint8_t z dann wird der Wert hochgezählt.
Offenischtlich handhabt das der avr-gcc unterschiedlich.
Bekommen aber bei compilieren den Hinweis
In function ‘test_var’:
warning: ‘z’ is used uninitialized in this function

Damit gestehe icvh meinen Denkfehler ein ;)

Vielen Dank für Eure Mühe und Geduld mit mir!!!

Hat jemand vielleicht noch ein Lösung für meine zweite Frage oben?
Gast
Johannes A. schrieb:
> von main periodisch aufgerufen, bringt immer 1
> schreibe ich static uint8_t z dann wird der Wert hochgezählt.
> Offenischtlich handhabt das der avr-gcc unterschiedlich.

nein macht er nicht. Es steht nur zufällig eine 0 drin. Das ganze ist 
abhängig vom Stack-Inhalt. (um genau zu sein, wird z vermutlich nur ein 
Register sein, wo zufällig eine 0 drin steht).

Darauf verlassen kann man sich auf keine Fall.
Johannes A. schrieb:
> Entweder ist das beobachtete so wie Du sagst oder der
> avr-gcc hilft hier nach.

Du kannst durch Beobachten nicht auf das Verhalten von C schließen.

Der Standard lässt einige Dinge offen, bzw überlässt das den 
Compilerherstellern.
Die können sich aber schon bei einer anderern Optimierungsstufe anders 
ausgelegt weerden.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 10 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.