【发布时间】:2016-07-12 09:52:20
【问题描述】:
我很难在我的 pebble watch 应用程序中找到一个奇怪的错误。我怀疑这是一个内存错误,但我找不到我的错误。我有一个字符串数组,当我调用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 循环中的每个字符串,最后一个字符总是以 null 结尾的字节,而前面的一个是句点(句子的结尾)。我不会在其他任何地方修改这些值,并且直到我的程序结束时才释放它们(因为它们应该在程序的生命周期中存在)。
我创建了一个具有动态条目数(在本例中为 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 有时会有所不同,解码字节和位置会根据字符串而变化。请注意,在日志中总是会为最后三个空白菜单项产生一些错误,即使滚动层不是空白并显示正确的文本(有时它会打印前三个到日志没有问题)。
我曾多次尝试在str_teasers 上使用APP_LOG,但当它失败时,它会在我调用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);
【问题讨论】:
-
您似乎没有
main函数。可执行语句必须在函数内。您是否将stdlib.h包括在malloc和string.h用于strcpy?您是否提供了自己的strtok?如果是这样,不建议复制库函数名称。请参阅MCVE。 -
这只是我的
main.c文件中的一个示例,它确实具有必要的main功能。实际功能要大得多,所以这只是相关部分。是的,我必须提供我自己的strtok,因为 pebble 不支持官方库名称,我是从 here 获得的。我已经检查过了,它似乎确实返回了以空字符结尾的正确字符串(无论如何strlen会返回 null 我相信如果不是)。 -
您需要添加有问题的可执行代码。我们无法执行的代码块很难提供帮助。此外,如果您在这里倾倒大量代码,那么您似乎并没有尝试自己缩小问题范围。
-
@Harry。只有当你有一块鹅卵石手表并且我为你提供了我所有的源代码时,这个问题才会重现。这就是为什么我提供了相关的评论部分和对我的错误的解释,希望有人能看到我可能遗漏的明显内容。
标签: c string pebble-watch pebble-sdk