更新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);
}
第二个版本会导致分配上的访问冲突异常。我确定这是因为第二个版本以不同的方式分配内存,但是我开始变得头疼,试图弄清楚什么或如何解决这个问题。 (我目前正在通过动态分配与模式数组相同大小的缓冲区,将模式复制到新缓冲区,对缓冲区进行更改,使用缓冲区代替模式数组,然后解决它试图记住释放临时缓冲区。)
(具体来说,原始版本将模式数组 - + offset-转换为DWORD *并为其分配一个DWORD常量来覆盖四个目标字节。新版本不能这样做,因为源的长度未知 - 可能不是四个字节 - 所以它使用memcpy。我已经检查并重新检查并确保指向memcpy的指针是正确的,但我仍然得到访问冲突。我使用memcpy而不是str(n)cpy因为我使用普通字符(作为字节数组),而不是Unicode字符并忽略空终止符。使用上面的赋值会导致同样的问题。)
有什么想法吗?
答案 0 :(得分:7)
尝试修改字符串文字是非法的。您的
Entries[0].pattern[2]='\x65';
行尝试就是这样。在第二个示例中,您没有为字符串分配任何内存。相反,您正在使用指针(在struct对象中)直接指向字符串文字。字符串文字不可修改。
每天都会多次询问这个问题。请阅读Why is this string reversal C code causing a segmentation fault?了解详情。
答案 1 :(得分:3)
问题归结为char[]
不是char*
这一事实,即使char[]
与表达式中的char*
非常相似。
答案 2 :(得分:3)
其他答案解决了错误的原因:您正在修改不允许的字符串文字。
此问题标记为C ++,因此解决问题的简便方法是使用std::string
。
struct ENTRY {
std::string pattern;
int somenum;
};
答案 3 :(得分: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也在堆栈中(就像在这个例子中那样),这不是问题,当然,因为它会在同一时间消失。
关于此的一些问答:
问:为什么我们不能在结构数组初始化中初始化字符串?答:因为字符串本身不在结构体中,并且初始化数组只为数组本身分配内存,而不是它指向的内容。
问:我们可以在结构中包含字符串吗?答:不;结构必须具有恒定的大小,并且字符串不具有恒定的大小。
问:这确实可以节省内存而不是字符串文字,然后malloc'ing存储并将字符串文字复制到其中,从而产生两个字符串副本,对吧?答:可能不是。当你写
char pattern[] = "\x12\x34\x56\x78";
会发生的是,文字值嵌入在已编译的代码中(就像字符串文字一样),然后执行该行时,内存将在堆栈上分配,代码中的值将被复制到记忆。所以你最终得到两个副本 - 源代码中的不可编辑版本(必须存在,因为它是初始值来自的地方),以及内存中其他地方的可编辑版本。这主要是关于源代码中的简单内容,以及帮助编译器优化其用于复制的指令。