我很难在我的卵石手表应用程序中查找一个奇怪的错误。我怀疑这是一个记忆错误,但我找不到我的错误。我有一个字符串数组,当我调用menu_layer = menu_layer_create(bounds);
时,它似乎在破坏我的字符串。我将在下面详细解释。错误的描述是粗体。
我有一个头文件,它将三个变量声明为extern,以便它们是全局的。
//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
这三个变量在main.c中修改,但在其他c文件中使用。下面是我的main.c文件的示例,其中我设置了字符串数组str_titles
和str_teasers
。结构info
包含两个非常长的字符串,但用分隔符|
分隔。我将这些字符串复制到临时缓冲区s_buffer
并用strtok
解析它们,将每个新字符串保存到我的字符串数组中。
这似乎运作良好,我已经检查了for循环中的每个字符串,最后一个字符始终是以空字符结尾的字节,而前一个字符是句点(句子的结尾)。我不会在其他任何地方修改这些值,并且我不会将它们释放到我的程序的最后阶段(因为它们应该存在于程序的生命中)。
我创建了一个包含动态条目数的菜单(在本例中为6),每个菜单都有str_titles
中6个字符串之一的标题。这里没有问题。我可以在我的程序中随时迭代和APP_LOG
这个字符串数组没有任何问题。
按下每个菜单项时,它应显示滚动图层中str_teasers
的较长字符串。它仅对前三个菜单项可靠地执行此操作。对于最后三个,它总是空白的。尝试使用APP_LOG
在此处迭代和打印字符串数组会在与pebble日志一起使用的python框架中产生一连串的错误,并且总是以类似的结尾:
UnicodeDecodeError: 'utf8' codec can't decode byte 0x98 in position 0: invalid start byte
最后一部分invalid start byte
有时会有所不同,解码字节和位置会根据字符串而变化。请注意,在日志中总是会为最后三个空白菜单项产生一些错误,有时只会产生前三个错误,即使滚动图层不是空白并显示正确的文本(前三个有时会打印出来)没有问题的日志。)
我已经在APP_LOG
的各个点尝试了str_teasers
,当它失败时,我会在致电menu_layer = menu_layer_create(bounds);
创建菜单后这样做。在我打电话之前,我可以用APP_LOG打印所有字符串,完全没有问题。我认为这是一个堆损坏错误,但我在创建图层之前和之后都有可用的堆内存(~8100字节),我的应用程序没有崩溃。
也许我错过了一些非常简单的事情,但我无法找到错误。我已经正确地为str_teasers
分配了内存,所以我不明白为什么要对其进行修改。我在下面提供了修改后的示例代码供参考。
//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 :(得分:3)
在此代码块中
// 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++;
}
您分配内存但立即用令牌指针覆盖指针。然后,在另一个类似的代码块中,你已经覆盖了这些指向的字符串。你可能已经“幸运”了,因为内存被重新分配,而之前的字符串内存仍然没有受到其他进程的影响。事实上,无论如何,你最终都要释放这个字符串缓冲区而不复制标记。
我认为你需要一个strcpy
// 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++;
}
与teasers代码块类似。
我还注意到你按counter
索引,但没有根据你提供的str_count
检查它,它用于为字符串指针数组分配内存。