Ich arbeite an den Übungen in K & Rs Buch, und ich habe einen seltsamen Bug beim Versuch, 04-06 zu erweitern Erlaube Variablen mit String-Namen. Ehrlich gesagt, habe ich es tatsächlich geschafft, den Fehler zu beheben (ziemlich einfach - unten erklärt), aber ich würde gerne wissen, warum der Fehler überhaupt aufgetreten ist.Das Übergeben einer nicht leeren Zeichenkette an snprintf bewirkt, dass ein nicht verwandtes char * -Array die Adressen ändert.
Für diejenigen, die mit dem Problem nicht vertraut sind, werden Sie grundsätzlich gebeten, einen Befehlszeilenrechner (in polnischer Notation) zu erstellen, der Variablen mit Charakternamen speichern und abrufen kann.
Hier ist der relevante Code, wo das Problem auftritt:
#define MAXOPLEN 1000
int varCount = 1;
char **keys;
char **values;
// changing the declaration to:
// char strOps[][STROPCOUNT] = { ... };
// fixed the issue
char *strOps[STROPCOUNT] = { "dupe", "swap", "del", "print",
"clr", "sin", "cos", "tan",
"exp", "pow", "ln", "log",
"mem", "re"};
main() {
keys = malloc(varCount * sizeof(char[MAXOPLEN]));
keys[0] = "ans";
values = malloc(varCount * sizeof(char[MAXOPLEN]));
values[0] = "0.0";
... // Other stuff related to the program
}
// flag is unrelated to the problem I'm asking about. It just checks to see
// if the variable name used to store value n is 'ans', which is where
// the last returned value is stored automatically
void memorize(char s[], double n, bool flag) {
... // small conditional block for flag
for (i = 0; i < varCount; i++) {
if (equals(keys[i], s)) {
found = True;
// Next line is where the program actually breaks
snprintf(values[i], MAXOPLEN, "%f", n);
break;
}
}
if (!found) {
i = varCount;
varCount++;
keys = realloc(keys, varCount * sizeof(char*));
keys[i] = malloc(sizeof(char[MAXOPLEN]));
keys[i] = s;
values = realloc(values, varCount * sizeof(char*));
values[i] = malloc(sizeof(char[MAXOPLEN]));
snprintf(values[i], MAXOPLEN, "%f", n);
}
}
Nach dem Kompilieren und Ausführen, zum ersten Mal in einer Gleichung eingeben zu berechnen, scheint alles glatt zu laufen. Beim Debugging habe ich jedoch festgestellt, dass die ersten drei char * in strOps merkwürdig auf unterschiedliche Adressen verweisen. Wenn Sie versuchen, den Rückgabewert der Gleichung auf "ans" zu speichern, wird die for-Schleife in memorize() eingefügt, die versucht, zu sehen, ob die Zeichenfolge s bereits als Schlüsselname verwendet wurde. Es findet korrekt die Schlüssel [0], um auf eine Zeichenkette zu zeigen, die dem s-Wert ("ans") entspricht, und versucht dann, n in eine Zeichenkette umzuwandeln und sie in Werten [0] zu speichern.
während im Innern des snprintf() -Funktion, die ersten drei char * in strops gemacht wird an anderer Stelle in diesem Verfahren in corecrt_stdio_config.h Punkt:
_Check_return_ _Ret_notnull_
__declspec(noinline) __inline unsigned __int64* __CRTDECL __local_stdio_printf_options(void)
{
// Error occurs after this next line:
static unsigned __int64 _OptionsStorage;
return &_OptionsStorage;
}
Wie oben in dem Code kommentiert, so dass ein 2D strops Ein Array von Zeichen (anstatt eines Arrays von Zeichenzeigern) behob das Problem. Dies ist sinnvoll, da in Zeichenfeldern die Werte einzelner Zeichen nicht geändert werden können. Was ich jedoch nicht verstehe, ist, warum die Methode in corecrt_stdio_config.h die Werte dieser drei Zeiger an erster Stelle ändert.
Danke!
Beginnen Sie mit der Verwendung korrekter Prototypfunktionsdeklaratoren. 'main()' ist veraltet. Und mit einem neueren Buch ist K & R längst überholt. Es lehrt kein modernes C! Und siehe [fragen], stellen Sie ein [mcve] zur Verfügung. Selbst wenn Ihr Code ohne Warnungen kompiliert wurde, ergibt das keinen Sinn. – Olaf
Und prüfen Sie das Ergebnis der Funktionen, wenn sie für die weitere Ausführung relevant sind! 'Realloc' könnte fehlschlagen! – Olaf