2016-03-24 20 views
0

Ich habe eine sehr harte Zeit, einen seltsamen Fehler in meiner Pebble Watch App zu verfolgen. Ich vermute, es ist ein Speicherfehler, aber ich kann meinen Fehler nicht finden. Ich habe eine Reihe von Saiten, und wenn ich menu_layer = menu_layer_create(bounds); rufe, scheint es irgendwie meine Saite zu verderben. Ich erkläre es unten ausführlicher. Die Beschreibung des Fehlers ist fett formatiert.String Korruption beim Aufruf von Menülayer

Ich habe eine Header-Dateien, die drei Variablen als extern deklariert, so dass sie global sind.

//externs.h 
#ifndef EXTERNS_H 
#define EXTERNS_H 

// These global variables are accessible by all source files. Modified in main.c 
extern int str_count; 
extern char **str_titles; 
extern char **str_teasers; 

#endif 

Diese drei Variablen sind in main.c geändert, werden aber in anderen c-Dateien verwendet. Unten ist ein Beispiel meiner main.c Datei, wo ich das Array der Zeichenfolgen str_titles und str_teasers setze. Die Struktur info enthält zwei Strings, die sehr lang sind, aber durch das Trennzeichen | getrennt sind. Ich kopiere diese Zeichenfolgen in einen temporären Puffer s_buffer und analysiere sie auseinander mit strtok und speichere jede neue Zeichenfolge in meinem Array von Zeichenfolgen.

Dies scheint gut zu funktionieren, ich habe jede Zeichenfolge in einer for-Schleife überprüft und das letzte Zeichen ist immer das nullterminierte Byte und das davor ist ein Punkt (Ende des Satzes). Ich ändere diese Werte nirgendwo anders, und ich befreie sie nicht bis zum Ende meines Programms (weil sie für das Leben des Programms existieren sollten).

Ich erstelle ein Menü mit einer dynamischen Anzahl von Einträgen (in diesem Fall 6), und jedes Menü hat den Titel einer der 6 Zeichenfolgen innerhalb str_titles. Hier gibt es keine Probleme. Ich kann durch und APP_LOG dieses Array von Strings ohne Probleme jederzeit in meinem Programm durchlaufen.

Wenn jeder Menüeintrag gedrückt wird, sollte die längere Zeichenfolge von str_teasers in einer Bildlaufebene angezeigt werden. Dies geschieht zuverlässig nur für die ersten drei Menüpunkte. Für die letzten drei ist es immer leer. das Array von Strings hier mit APP_LOG erzeugt eine Litanei von Fehlern in der Python-Framework mit den Kies Protokolle und endet immer mit so etwas wie verwendet iterieren Der Versuch, und drucken:

UnicodeDecodeError: 'utf8' codec can't decode byte 0x98 in position 0: invalid start byte 

Der letzte Teil invalid start byte ist manchmal etwas anderes und die Decodierbytes und Position ändert sich basierend auf der Zeichenfolge. Beachten Sie, dass in den Protokollen immer ein Fehler für die letzten drei leeren Menüelemente auftritt, und nur manchmal den Fehler für die ersten drei erzeugt, auch wenn die Bildlaufebene nicht leer ist und den richtigen Text anzeigt (für die ersten drei wird manchmal gedruckt zu den Protokollen ohne Problem).

Ich habe APP_LOG auf str_teasers an verschiedenen Punkten versucht, und wenn es fehlschlägt, tut sie dies, nachdem ich menu_layer = menu_layer_create(bounds); mein Menü erstellen rufen. Bevor ich diesen Aufruf tätige, kann ich alle Zeichenfolgen mit APP_LOG ohne Probleme ausgeben. Ich dachte, es wäre ein Heap-Fehler, aber ich habe Heap-Speicher (~ 8100 Bytes) vor und nach der Erstellung des Layers und meine App stürzt nicht ab.

Vielleicht vermisse ich etwas sehr einfach, aber ich kann meinen Fehler nicht finden. Ich habe den Speicher für str_teasers richtig zugeordnet, glaube ich, also sehe ich nicht, warum es überhaupt geändert werden sollte. Ich habe einen modifizierten Beispielcode als Referenz eingefügt.

//main.c 
#include "strtok.h" 
#include "externs.h" 

int str_count; 
char **str_titles; 
char **str_teasers; 

char *s_buffer; 
const char delim[1] = "|"; 
char *token; 

typedef struct { 
    int s_count; 
    char* s_titles; 
    char* s_teasers; 
} s_info; 
s_info info; 


// Sample code 

str_count = info.s_count; 

// Declare arrays of appropriate size 
str_titles = malloc(str_count * sizeof(char*)); 
str_teasers = malloc(str_count * sizeof(char*)); 

// This creates a copy of the entire string s_titles into s_buffer 
int len = strlen(info.s_titles) + 1; 
s_buffer = (char *)malloc(len); 
strcpy(s_buffer, info.s_titles); 

token = strtok(s_buffer, delim); // Get the first token for the titles 

// Walk through the other tokens 
int counter = 0; 
while(token != NULL) { 
    *(str_titles + counter) = malloc((strlen(token) + 1) * sizeof(char)); 
    *(str_titles + counter) = token; 
    token = strtok(NULL, delim); 
    counter++; 
} 

// This creates a copy of the entire string s_teasers into s_buffer 
len = strlen(info.s_teasers) + 1; 
s_buffer = (char *)realloc(s_buffer, len); 
strcpy(s_buffer, info.s_teasers); 

token = strtok(s_buffer, delim); // Get the first token for the teasers 

// Walk through the other tokens 
counter = 0; 
while(token != NULL) { 
    *(str_teasers + counter) = malloc((strlen(token) + 1) * sizeof(char)); 
    *(str_teasers + counter) = token; 
    token = strtok(NULL, delim); 
    counter++; 
} 
free(s_buffer); 
+0

Sie scheinen keine 'Hauptfunktion 'zu haben. Ausführbare Anweisungen müssen innerhalb einer Funktion sein. Haben Sie 'stdlib.h' für' malloc' und 'string.h' für' strcpy' eingeschlossen? Haben Sie Ihren eigenen 'strtok' geliefert? In diesem Fall ist es nicht ratsam, den Namen einer Bibliotheksfunktion zu duplizieren. Siehe [MCVE] (http://stackoverflow.com/help/mcve). –

+0

Dies ist nur ein Beispiel aus meiner 'main.c' Datei, es hat die erforderliche' main' Funktion. Die eigentliche Funktion ist viel größer, so dass dies nur die relevanten Teile sind. Und ja, ich musste mein eigenes 'strtok' liefern, weil Pebble den offiziellen Bibliotheksnamen nicht unterstützt, ich habe es von [hier] (http://www.opensource.apple.com/source/Libc/Libc-167/string) .subproj/strtok.c). Ich habe es überprüft und es scheint die richtigen Zeichenfolgen zurückzugeben, die mit einem Nullzeichen enden (jedenfalls würde 'strlen' null zurückgeben, glaube ich, wenn es nicht wäre). –

+1

Sie müssen ausführbaren Code hinzufügen, der das Problem aufweist. Ein Klecks Code, den wir nicht ausführen können, ist schwer zu helfen. Außerdem, wenn Sie hier tonnenweise Code ausgeben, dann sieht es so aus, als hätten Sie nicht versucht, das Problem selbst einzugrenzen. – Harry

Antwort

3

In diesem Codeblock

// Walk through the other tokens 
int counter = 0; 
while(token != NULL) { 
    *(str_titles + counter) = malloc((strlen(token) + 1) * sizeof(char)); 
    *(str_titles + counter) = token; 
    token = strtok(NULL, delim); 
    counter++; 
} 

Sie Speicher zuweisen, sondern sofort den Zeiger mit dem Token-Zeiger überschrieben. Dann haben Sie in dem anderen, ähnlichen Codeblock die Zeichenfolge überschrieben, auf die diese zeigen. Sie könnten "glücklich" gewesen sein, da der Speicher neu zugewiesen wurde und der vorherige Zeichenfolgenspeicher von anderen Prozessen noch nicht bearbeitet wurde. Und tatsächlich enden Sie damit, dass Sie diesen String-Puffer sowieso freigeben, ohne die Token kopiert zu haben.

Ich glaube, Sie brauchen eine strcpy hier

// Walk through the other tokens 
int counter = 0; 
while(token != NULL) { 
    *(str_titles + counter) = malloc((strlen(token) + 1) * sizeof(char)); 
    strcpy(*(str_titles + counter), token);   // <<--- here 
    token = strtok(NULL, delim); 
    counter++; 
} 

Ebenso für den Codeblock Teasern.

Ich merke auch, dass Sie von counter indizieren, aber haben es nicht gegen die str_count, die Sie mit geliefert wurden, die verwendet wurde, um Speicher für das Array von String-Zeigern zu reservieren.

+1

Ja, Sie haben Recht, ich habe Ihre Korrektur vorgenommen und es funktioniert wie erwartet. Ich hatte Glück, bevor ich vermutete, dass es passierte, aber ich wusste nicht warum. Ich bin immer noch ein bisschen eingerostet mit C, manchmal vermisse ich wirklich offensichtliche Fehler wie diese. Außerdem überprüfe ich 'str_count' nicht gegen Zähler, da ich 100% sicher bin, dass es in meinem Array die gleiche Anzahl an Strings geben wird wie der Wert von str_count. Dies sind Variablen, die von einer Companion-.js-App stammen, wobei die Anzahl der Strings explizit vom Wert von 'str_count' abhängt. Danke für Ihre Hilfe! –

+1

Danke für die Abstimmung! Zur Überprüfung des Bereichs: * NIEMALS * vertraue einer externen Datenquelle. Sei robust. Es könnte ein Schmerz sein zu implementieren, aber wenn Sie dies zu Ihrem Arbeitsstil machen, wird es sich auszahlen. –

+1

Das ist ein sehr guter Vorschlag, danke. Ich werde sicher sein, diese Überprüfung zu implementieren, um die Robustheit zu verbessern. –

Verwandte Themen