1

更新 2:

好吧,我已经将我拥有的解决方法重构为一个单独的函数。这样,虽然它仍然不理想(特别是因为我必须在函数外部释放函数内部分配的内存),但它确实提供了更普遍地使用它的能力。我仍然希望有一个更优化和优雅的解决方案……


更新:

好的,所以问题的原因已经确定,但我仍然无所适从。

我试图找出一种(简单/有效)的方法来修改结构中数组的几个字节。我目前的解决方法是动态分配大小相等的缓冲区、复制数组、对缓冲区进行更改、使用缓冲区代替数组,然后释放缓冲区似乎过多且不太理想。如果我必须这样做,我不妨将两个数组放入结构中并将它们初始化为相同的数据,然后在第二个中进行更改。我的目标是减少内存占用(仅存储原始数组和修改后的数组之间的差异)和手动工作量(自动修补数组)。


原帖:

我昨晚写了一个运行良好的程序,但是当我今天重构它以使其更具可扩展性时,我遇到了一个问题。

原始版本有一个硬编码的字节数组。经过一些处理后,一些字节被写入数组,然后进行了一些处理。

为了避免对模式进行硬编码,我将数组放在一个结构中,以便我可以添加一些相关数据并创建它们的数组。但是现在,我无法写入结构中的数组。这是一个伪代码示例:

main() {
  char pattern[]="\x32\x33\x12\x13\xba\xbb";
  PrintData(pattern);
  pattern[2]='\x65';
  PrintData(pattern);
}

那个有效,但这个无效:

struct ENTRY {
  char* pattern;
  int   somenum;
};

main() {
  ENTRY Entries[] = {
      {"\x32\x33\x12\x13\xba\xbb\x9a\xbc", 44}
    , {"\x12\x34\x56\x78", 555}
  };
  PrintData(Entries[0].pattern);
  Entries[0].pattern[2]='\x65';   //0xC0000005 exception!!! :(
  PrintData(Entries[0].pattern);
}

第二个版本导致分配上的访问冲突异常。我确定这是因为第二个版本分配内存的方式不同,但我开始头疼,试图弄清楚是什么或如何解决这个问题。(我目前正在通过动态分配与模式数组大小相同的缓冲区、将模式复制到新缓冲区、对缓冲区进行更改、使用缓冲区代替模式数组来解决它,然后试图记住释放临时缓冲区。)

(具体来说,原始版本将模式数组(+偏移量)转换为 DWORD* 并为其分配一个 DWORD 常量以覆盖四个目标字节。新版本不能这样做,因为源的长度是未知的——可能不是四个字节——所以它使用 memcpy 代替。我已经检查并重新检查并确保指向 memcpy 的指针是正确的,但我仍然遇到访问冲突。我使用 memcpy 而不是 str(n)cpy 因为我是使用普通字符(作为字节数组),而不是 Unicode 字符并忽略空终止符。使用上述赋值会导致同样的问题。)

有任何想法吗?

4

4 回答 4

7

尝试修改字符串文字是非法的。您的

Entries[0].pattern[2]='\x65'; 

line 正是这样做的。在您的第二个示例中,您没有为字符串分配任何内存。相反,您正在使指针(在结构对象中)直接指向字符串文字。并且字符串文字是不可修改的。

这个问题每天都会被问好几次。阅读为什么这个字符串反转 C 代码会导致分段错误?更多细节。

于 2010-04-10T00:07:38.440 回答
3

问题归结为 achar[]不是 a的事实char*,即使它的char[]行为很像char*表达式中的 a 。

于 2010-04-10T00:08:54.363 回答
3

其他答案已经解决了错误的原因:您正在修改不允许的字符串文字。

这个问题被标记为 C++,所以解决问题的简单方法是使用std::string.

struct ENTRY {
  std::string pattern;
  int         somenum;
};
于 2010-07-22T20:27:37.303 回答
1

根据您的更新,您真正的问题是:您想知道如何以可编辑的方式初始化结构数组中的字符串。(这个问题与创建结构数组后发生的事情无关——正如您在示例代码中所展示的那样,如果它们被正确初始化,编辑字符串就很容易了。)

以下代码示例显示了如何执行此操作:

// Allocate the memory for the strings, on the stack so they'll be editable, and
// initialize them:
char ptn1[] = "\x32\x33\x12\x13\xba\xbb\x9a\xbc";
char ptn2[] = "\x12\x34\x56\x78";

// Now, initialize the structs with their char* pointers pointing at the editable
// strings:
ENTRY Entries[] = {
  {ptn1, 44}
, {ptn2, 555}
};

那应该可以正常工作。但是,请注意,字符串的内存在堆栈上,因此如果您离开当前范围,它将消失。当然,如果 Entries 也在堆栈上(如本例中所示),这不是问题,因为它会同时消失。

对此的一些问答:

问:为什么我们不能在array-of-structs初始化中初始化字符串?A:因为字符串本身不在结构体中,初始化数组只为数组本身分配内存,而不是为它指向的东西分配内存。

问:那么我们可以在结构中包含字符串吗?答:没有;结构必须具有恒定大小,并且字符串没有恒定大小。

问:这确实节省了内存,而不是拥有一个字符串文字,然后 malloc'ing 存储并将字符串文字复制到其中,从而导致字符串的两个副本,对吗?答:可能不会。当你写

char pattern[] = "\x12\x34\x56\x78";

发生的情况是该文字值嵌入到您的编译代码中(基本上就像字符串文字一样),然后当该行执行时,内存被分配到堆栈上,代码中的值被复制到该内存中。因此,无论如何,您最终都会得到两个副本——源代码中的不可编辑版本(必须存在,因为它是初始值的来源),以及内存中其他地方的可编辑版本。这实际上主要是关于源代码中的简单之处,还有一点是关于帮助编译器优化它用来进行复制的指令。

于 2010-04-10T05:48:48.233 回答