动态增加 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 保留为非空终止。但是,要转换为字符串,您必须在读取所有其他字符后添加最后一个空字符。

  1. const char *str - 你声明指向 const char 的指针。您不能写入引用的对象,因为它调用 UB
  2. 您使用 sprintf 只是为了添加 char。没有意义。
  3. 结构中不需要指针。

您需要设置编译器选项来编译**作为 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 读取的源内存与目标内存重叠。

相反,您需要使用其他一些方法来附加不涉及重叠读写的字符(例如,使用 [ ] 运算符写入字符并且不要忘记空终止) .