动态增加 C 字符串的大小
Dynamically increasing C string's size
我目前正在创建一个程序来捕获用户的按键并将它们存储在一个字符串中。我希望存储按键的字符串是动态的,但我遇到了一个问题。
我当前的代码如下所示:
#include <stdio.h>
#include <stdlib.h>
typedef struct Foo {
const char* str;
int size;
} Foo;
int main(void)
{
int i;
Foo foo;
foo.str = NULL;
foo.size = 0;
for (;;) {
for (i = 8; i <= 190; i++) {
if (GetAsyncKeyState(i) == -32767) { // if key is pressed
foo.str = (char*)realloc(foo.str, (foo.size + 1) * sizeof(char)); // Access violation reading location xxx
sprintf(foo.str, "%s%c", foo.str, (char)i);
foo.size++;
}
}
}
return 0;
}
任何帮助将不胜感激,因为我没有任何想法了。 :(
我是否也应该动态分配 Foo 对象?
首先,为了更好地处理事情,你需要定义
typedef struct Foo {
char* str;
int size
} Foo;
否则,Foo 正确地变异真的很烦人 - 您可以通过以任何方式在 realloc 调用之后修改 foo->str
来调用未定义的行为。
段错误实际上是由sprintf(foo.str, "%s%c", foo.str, (char)i);
引起的,而不是对realloc
的调用。 foo.str
通常不以 null 结尾。
实际上,调用 sprintf
根本就是在重复工作。 realloc
已经复制了之前 f.str
中的所有字符,因此您只需通过
添加一个字符
f.str[size] = (char) i;
编辑以回复评论:
如果我们想一起附加到字符串(或者更确切地说,两个 Foos),我们可以这样做:
void appendFoos(Foo* const first, const Foo* const second) {
first->str = realloc(first->str, (first->size + second->size) * (sizeof(char)));
memcpy(first->str + first->size, second->str, second->size);
first->size += second->size;
}
appendFoos
函数通过在其上附加 second
来修改 first
。
在这段代码中,我们将 Foos
保留为非空终止。但是,要转换为字符串,您必须在读取所有其他字符后添加最后一个空字符。
const char *str
- 你声明指向 const char
的指针。您不能写入引用的对象,因为它调用 UB
- 您使用
sprintf
只是为了添加 char
。没有意义。
- 结构中不需要指针。
您需要设置编译器选项来编译**作为 C 语言”而不是 C++
我会以不同的方式来做:
typedef struct Foo {
size_t size;
char str[1];
} Foo;
Foo *addCharToFoo(Foo *f, char ch);
{
if(f)
{
f = realloc(f, sizeof(*f) + f -> size);
}
else
{
f = realloc(f, sizeof(*f) + 1);
if(f) f-> size = 0
}
if(f) //check if realloc did not fail
{
f -> str[f -> size++] = ch;
f -> str[f -> size] = 0;
}
return f;
}
并在 main
int main(void)
{
int i;
Foo *foo = NULL, *tmp;
for (;;)
{
for (i = 8; i <= 190; i++)
{
if (GetAsyncKeyState(i) == -32767) { // if key is pressed
if((tmp = addCharToFoo(f, i))
{
foo = tmp;
}
else
/* do something - realloc failed*/
}
}
}
return 0;
}
sprintf(foo.str, "%s%c", foo.str, (char)i);
格式错误:第一个参数不能是 const char *
。您应该会看到一条编译器错误消息。
修复此问题(使 str
成为 char *
)后,行为未定义,因为 %s
读取的源内存与目标内存重叠。
相反,您需要使用其他一些方法来附加不涉及重叠读写的字符(例如,使用 [ ]
运算符写入字符并且不要忘记空终止) .
我目前正在创建一个程序来捕获用户的按键并将它们存储在一个字符串中。我希望存储按键的字符串是动态的,但我遇到了一个问题。 我当前的代码如下所示:
#include <stdio.h>
#include <stdlib.h>
typedef struct Foo {
const char* str;
int size;
} Foo;
int main(void)
{
int i;
Foo foo;
foo.str = NULL;
foo.size = 0;
for (;;) {
for (i = 8; i <= 190; i++) {
if (GetAsyncKeyState(i) == -32767) { // if key is pressed
foo.str = (char*)realloc(foo.str, (foo.size + 1) * sizeof(char)); // Access violation reading location xxx
sprintf(foo.str, "%s%c", foo.str, (char)i);
foo.size++;
}
}
}
return 0;
}
任何帮助将不胜感激,因为我没有任何想法了。 :(
我是否也应该动态分配 Foo 对象?
首先,为了更好地处理事情,你需要定义
typedef struct Foo {
char* str;
int size
} Foo;
否则,Foo 正确地变异真的很烦人 - 您可以通过以任何方式在 realloc 调用之后修改 foo->str
来调用未定义的行为。
段错误实际上是由sprintf(foo.str, "%s%c", foo.str, (char)i);
引起的,而不是对realloc
的调用。 foo.str
通常不以 null 结尾。
实际上,调用 sprintf
根本就是在重复工作。 realloc
已经复制了之前 f.str
中的所有字符,因此您只需通过
f.str[size] = (char) i;
编辑以回复评论:
如果我们想一起附加到字符串(或者更确切地说,两个 Foos),我们可以这样做:
void appendFoos(Foo* const first, const Foo* const second) {
first->str = realloc(first->str, (first->size + second->size) * (sizeof(char)));
memcpy(first->str + first->size, second->str, second->size);
first->size += second->size;
}
appendFoos
函数通过在其上附加 second
来修改 first
。
在这段代码中,我们将 Foos
保留为非空终止。但是,要转换为字符串,您必须在读取所有其他字符后添加最后一个空字符。
const char *str
- 你声明指向const char
的指针。您不能写入引用的对象,因为它调用 UB- 您使用
sprintf
只是为了添加char
。没有意义。 - 结构中不需要指针。
您需要设置编译器选项来编译**作为 C 语言”而不是 C++
我会以不同的方式来做:
typedef struct Foo {
size_t size;
char str[1];
} Foo;
Foo *addCharToFoo(Foo *f, char ch);
{
if(f)
{
f = realloc(f, sizeof(*f) + f -> size);
}
else
{
f = realloc(f, sizeof(*f) + 1);
if(f) f-> size = 0
}
if(f) //check if realloc did not fail
{
f -> str[f -> size++] = ch;
f -> str[f -> size] = 0;
}
return f;
}
并在 main
int main(void)
{
int i;
Foo *foo = NULL, *tmp;
for (;;)
{
for (i = 8; i <= 190; i++)
{
if (GetAsyncKeyState(i) == -32767) { // if key is pressed
if((tmp = addCharToFoo(f, i))
{
foo = tmp;
}
else
/* do something - realloc failed*/
}
}
}
return 0;
}
sprintf(foo.str, "%s%c", foo.str, (char)i);
格式错误:第一个参数不能是 const char *
。您应该会看到一条编译器错误消息。
修复此问题(使 str
成为 char *
)后,行为未定义,因为 %s
读取的源内存与目标内存重叠。
相反,您需要使用其他一些方法来附加不涉及重叠读写的字符(例如,使用 [ ]
运算符写入字符并且不要忘记空终止) .