调用menu_layer

时间:2016-03-24 17:29:41

标签: c string pebble-watch pebble-sdk

我很难在我的卵石手表应用程序中查找一个奇怪的错误。我怀疑这是一个记忆错误,但我找不到我的错误。我有一个字符串数组,当我调用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_titlesstr_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);

1 个答案:

答案 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检查它,它用于为字符串指针数组分配内存。