Probleme beim Übergeben eines Arrays an eine Funktion
-
Hallo,
ich habe ein Array was ich an eine Funktion übergebe.
Das Array ist mehrdimensional.SO initialisiere und bespiele ich es:
char selectbox_list_values[MAX_SB_LISTS][MAX_SB_LISTENTRIES][MAX_SB_ENTRYSIZE] = { 0 }; int set_sbl_entry(int selectbox_id, int entry_id, char *new_value) { strncpy(selectbox_list_values[selectbox_id][entry_id], new_value, MAX_SB_ENTRYSIZE); return 0; } void build_list_entries() { set_sbl_entry( FREQUENCY_LIST, 0, "50 Hz"); }
Ich habe dann eine Funktion der ich die Liste übergebe und dir eine Schleife durchlaufen soll für jeden Listen eintrag:
//Funktionsaufruf write_select_box(selectbox_list_values[FREQUENCY_LIST], fdm_powerline_frequency, "fdm powerline frequency", "Frequency"); //Funktion void write_select_box(char *fooarr[], char value_var[], char *label, char *keyname) { static int i; if ( strlen( fooarr[i] ) != 0 ) { printf("<span class=cfglabel style=\"width:190px;\">%s </span><select name=\"%s\" style=\"width:100px;\">", label, keyname); for(i = 0; i <MAX_SB_LISTENTRIES; i++) { printf("<option value='%s'", fooarr[i] ); if (strcmp(value_var, fooarr[i]) == 0) { printf(" selected"); } printf(">%s</option>", fooarr[i]); } printf("</select><br><br>"); } }
Jetzt habe ich mehrere Probleme. Wenn ich das fooarr als Pointer übergebe meckert der compiler das es weder ein array noch ein pointer ist.
Vielleicht weiß da einer Abhilfe bzw nen Rat.
Danke schon einmal im Voraus.
-
Versuche es mal mit
void write_select_box(char fooarr[][MAX_SB_ENTRYSIZE], char value_var[], char *label, char *keyname) {
- globale Variablen sind Müll
- lokalstatische Variablen sind Müll
- der Gebrauch von strncpy ist Müll, kann bei dir leicht in UB münden
- ...
-
Jetzt meckert das ding nimmer.
Allerdings gibt die funktion nun auch nix mehr aus.
Zusätzlich hab ich noch ein problem.
main.c:35: warning: missing braces around initializer
main.c:35: warning: (near initialization for 'selectbox_list_values[0]')Die Zeile sieht so aus
char selectbox_list_values[MAX_SB_LISTS][MAX_SB_LISTENTRIES][MAX_SB_ENTRYSIZE] = { 0 };
-
Ich bin hier etwas weiter gekommen.
Ich glaube das Problem liegt beim Zugriff auf die Array Elemente.
Das Array wird wie folgt befüllt:
char selectbox_list_values[MAX_SB_LISTS][MAX_SB_LISTENTRIES][MAX_SB_ENTRYSIZE] = {{{0}}}; int set_sbl_entry(int selectbox_id, int entry_id, char *new_value) { strncpy(selectbox_list_values[selectbox_id][entry_id], new_value, MAX_SB_ENTRYSIZE); return 0; } void build_list_entries() { set_sbl_entry( FREQUENCY_LIST, 0, "50 Hz"); set_sbl_entry( FREQUENCY_LIST, 1, "60 Hz"); set_sbl_entry( BAUDRATE_LIST, 0, "300"); set_sbl_entry( BAUDRATE_LIST, 1, "600"); set_sbl_entry( BAUDRATE_LIST, 2, "1200"); set_sbl_entry( BAUDRATE_LIST, 3, "2400"); set_sbl_entry( BAUDRATE_LIST, 4, "4800"); set_sbl_entry( BAUDRATE_LIST, 5, "9600"); set_sbl_entry( BAUDRATE_LIST, 6, "19200"); set_sbl_entry( FRAMING_LIST, 0, "7E1"); set_sbl_entry( FRAMING_LIST, 1, "7E2"); set_sbl_entry( FRAMING_LIST, 2, "702"); set_sbl_entry( FRAMING_LIST, 3, "7N2"); set_sbl_entry( FRAMING_LIST, 4, "8E1"); set_sbl_entry( FRAMING_LIST, 5, "8N2"); set_sbl_entry( FRAMING_LIST, 6, "8N1"); set_sbl_entry( FRAMING_LIST, 7, "801"); set_sbl_entry( STRING_FORMAT_LIST, 0, "STANDARD"); set_sbl_entry( STRING_FORMAT_LIST, 1, "TTM1"); set_sbl_entry( STRING_FORMAT_LIST, 2, "TTM2"); set_sbl_entry( MONITOR_LIST, 0, "0"); set_sbl_entry( MONITOR_LIST, 1, "1"); set_sbl_entry( FDM_ANALOGUE_LIST, 0, "500mhz"); set_sbl_entry( FDM_ANALOGUE_LIST, 1, "5Hz"); set_sbl_entry( FDM_ANALOGUE_LIST, 2, "10s"); set_sbl_entry( FDM_ANALOGUE_LIST, 3, "100s"); }
Anscheinend funktioniert der Zugriff auf fooarr[i] innerhalb der Funktion nicht bzw der Wert ist (null).
Einer eine Idee??
-
Wutz schrieb:
- lokalstatische Variablen sind Müll
Kannst du das näher erläutern? Was ist denn gegen statische Variablen in Funktionen im Allgemeinen zu sagen?
-
Lokalstatische Variablen (globale Variablen sind auch immer (implizit) static, aber eben global sichtbar) schaffen unnötige, zusätzliche Abhängigkeiten in deinem Programm, der Erstaufruf dieser Funktion läuft per se anders als die folgenden.
Weiterhin wird ein sinnvolles Inlining der Funktion durch den Compiler verhindert.
Weiterhin wird Multithreading verhindert.
Mit Reentranz siehst es demzufolge auch schlecht aus.
Ganz schlecht sieht es aus, wenn diese lokalstatischen Speicherbereiche als Zeiger returniert werden und mit diesen Zeigern dann weiteroperiert wird (die nächste Dereferenzierung bringt u.U. nicht erwartete Ergebnisse: viel Spaß beim Debuggen).
Außerdem kann der Compiler derlei Designfehler nicht mehr bemängeln.
Ein Beispiel mal kurz:const char* inKlammern(const char *s) { static char r[1000]; strcpy(r,"("); strcat(r,s); return strcat(r,")"); } int main() { printf("%s",inKlammern("hello")); /* funktioniert */ printf("%s%s",inKlammern("hello"),inKlammern("world")); /* funktioniert höchstwahrscheinlich nicht, gibt aber auch keine Warnungen */ return 0; }
Meistens sind diese (wie gesagt meist völlig unnötigen und aus Faulheit des Programmierers heraus entstandenen) Abhängigkeiten auch noch wenig bis gar nicht in entsprechender Weise dokumentiert, ich schließe da die Standardbibliothek nicht aus:
localtime/gmtime
strtok
rand/srand
mbsrtowcs/mbsrtowc
setlocale
...
Deshalb empfiehlt sich immer, über die Funktion hinaus benötigte Speicherbereiche auch von außen zu verwalten und im Bedarfsfall der Funktion als Parameter zu übergeben, verschiedene Versuche dazu gibt es:
strtok / strtok_r
...
-
Ok, gut, aber man kann sich das Leben natürlich immer schwer machen und besonders bescheuert programmieren. Warum sollte man Zeiger auf statischen Speicher zurückgeben? Ich verwende statische Variablen nur, um in Funktionen Zustände zu speichern.
Ich programmiere momentan auf Mikrocontrollern (avr) und da finde ich lokalstatische variablen sehr praktisch. Z.b. bei einer interruptroutine, die einen Wert (eine Taste) von einem Eingabegerät erhält. Um das mit der vorherigen Taste zu vergleichen, finde ich statische variablen eigentlich eine schöne Lösung. Ich bin aber kein Experte, vielleicht geht das ja besser. Ich bin da offen für neues
!
Zu deinen anderen Punkten:
Wenn die Funktion nicht ge-inlined wird, naja dann halt nicht.
Multithreading werde ich hier nicht haben.
Und wo ist das problem mit dem Erstaufruf?
In meinem Beispiel:ISR(INT0_vect) { static uint8_t vorherige_taste = 0xFF; /* die Tasten belegen nur 3 Bit, 0xFF kann also gar nicht vorkommen */ /* ... */ }
Ist doch prima: Beim ersten Aufruf steht ein ungültiger Wert drin, das heißt das alle Vergleiche mit tatsächlichen Tasten false ergeben!
Naja, ist aber auch nicht so wichtig.
-
Ist ja alles schön und gut.
Aber hat noch einer nen Rat zu meinem Problem mit dem Array bzw mit der Liste aus gültigen Werten die von der Schleife bearbeitet werden soll?
-
Evilmachine schrieb:
Aber hat noch einer nen Rat zu meinem Problem mit dem Array bzw mit der Liste aus gültigen Werten die von der Schleife bearbeitet werden soll?
Der Code ist voll mit Details, die nicht interessieren, bzw. uns nicht zur Verfügung stehen.
Warum schreibst Du nicht ein kurzes Beispiel ohne HTML und Klimbim, das Dein Problem wiederspiegelt?
Hier z.B.:#include <stdio.h> #include <string.h> #define ENTRIES 3 #define ENTRYLEN 16 enum {LIST_A, LIST_B, LIST_C, LISTS}; char array[LISTS][ENTRIES][ENTRYLEN] = {{{0}}}; void set_entry(int list, int entry, const char* val){ strncpy(array[list][entry], val, ENTRYLEN); array[list][entry][ENTRYLEN-1]='\0'; } void fill(void){ set_entry(LIST_A, 0, "zytosolisch"); set_entry(LIST_A, 1, "zytostatika"); set_entry(LIST_A, 2, "zytostatikum"); set_entry(LIST_C, 0, "zytostatisch"); set_entry(LIST_C, 2, "zytotoxisch"); } void mark(char list[][ENTRYLEN], const char* val){ for(int i=0; i<ENTRIES; ++i) if(strcmp(val, list[i])==0) printf("**** %s ****\n", list[i]); else printf(" %s \n", list[i]); } int main(void){ fill(); mark(array[LIST_C], "zytotoxisch"); mark(array[LIST_C], "antibakteriell"); }
Das kommt dem, was Du willst wohl recht nahe und ist auch auf kleinen Bildschirmen übersichtlich.