如何将字符收集到 C 中的字符串中?

How do I collect chars into a string in C?

我需要将一些字符收集到我的词法分析器的缓冲区中,但我不知道如何操作。我已经阅读了一些关于 Whosebug 的答案,但这些是不同的情况。我有一个读取下一个字符的 while 循环,我想将逻辑放入其中,以便将新字符附加到内存中的缓冲区。

// init buffer with the first char 'h'
char *buffer = malloc(sizeof(char));
buffer[0] = 'h';
buffer[1] = '[=10=]';

// go through input char by char
while(...)
{
   char c = read_next_char(); 
   buffer.append(c) // I whould do in JavaScript, but not in C :(
}


在您的情况下,您在开头分配一个字节 char *buffer = malloc(sizeof(char)); 并访问缓冲区 [1] 或任何其他索引是 UB。

您可以在开始时分配已知数量的字节并使用它,直到您看到需要更多缓冲区大小的点。

像这样,

int buffersize = 100;
int index =0;
char *buffer = malloc(sizeof(char)*buffersize); //100bytes are allocated

if(!buffer)
    return;

buffer[index++] = 'h';
buffer[index++] = '[=10=]';

// go through input char by char
while(...)
{
   char c = read_next_char(); 
   if(index == buffersize ){
      buffersize +=100;
       buffer= realloc(buffer, buffersize );
      //here buffer size is increased by 100
       if(!buffer) 
           return;
   }
   
   buffer[index++] = c ;
}

注意:您必须在使用结束后释放buffer,否则会导致资源泄漏。

您需要简单地覆盖空终止字符并添加新字符。

char *append(char *buff, int ch)
{
    size_t len = strlen(buff);
    buff[len] = ch;
    buff[len+1] = 0;
    return buff;
}

代码假定 buff 是一个有效指针,指向足够长的内存块以容纳新的 char 和 null 终止 char。它必须包含有效的 C 字符串。

与java或javascipt不同,C中没有字符串类型,您需要自己编写。

这是一个非常简单的示例,说明了如何有效地处理字符串的构建。

不言自明。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct DynamicString
{
  char* string;    // pointer to string
  int length;      // string length
  int capacity;    // capacity of the string buffer (= allocated size)
};

#define DS_CHUNKSIZE 100   // we increase the buffer size by DS_CHUNKSIZE
                           // change this as needed

// Initialize the structure
void InitDynamicString(struct DynamicString* ds)
{
  ds->capacity = DS_CHUNKSIZE + 1;
  ds->string = malloc(ds->capacity);
  ds->string[0] = 0;   // null terminator
  ds->length = 0;      // initial string length 0
};

// Increase the string buffer size if necessary
// (internal function)
void IncreaseSize(struct DynamicString* ds, int newsize)
{
  if (ds->length + newsize + 1 > ds->capacity)
  {
    ds->capacity = ds->length + newsize + DS_CHUNKSIZE + 1;
    ds->string = realloc(ds->string, ds->capacity); // reallocate a new larger buffer
  }
}

// append a single character
void AppendChar(struct DynamicString* ds, char ch)
{
  IncreaseSize(ds, sizeof(char)); // increase size by 1 if necessary
  ds->string[ds->length++] = ch;  // append char
  ds->string[ds->length] = 0;     // null terminator
}

// append a string
void AppendString(struct DynamicString* ds, const char *str)
{
  IncreaseSize(ds, strlen(str));  // increase by length of string if necessary
  strcat(ds->string, str);        // concatenate
  ds->length += strlen(str);      // update string length
}


int main(int argc, char* argv[])
{
  struct DynamicString ds;

  InitDynamicString(&ds);   // initialize ds

  AppendChar(&ds, 'a');     // append chars
  AppendChar(&ds, 'b');
  AppendChar(&ds, 'c');

  AppendString(&ds, "DE");      // append strings
  AppendString(&ds, "xyz1234");

  printf("string = \"%s\"", ds.string);  // show result
}

您的代码可以像这样使用它:

struct DynamicString buffer;
InitDynamicString(&buffer)

dAppendChar(&buffer, 'h');

while(...)
{
   char c = read_next_char(); 
   AppendChar(&buffer, c); // quite similar to  buffer.append(c)
}

免责声明:

  • 代码尚未经过全面测试,可能存在错误。
  • 没有任何错误检查。 mallocrealloc 可能会失败。
  • 其他有用的函数如SetString(struct DynamicString *ds, const char *string)需要写
  • 还有优化的空间,尤其是 strcat 可以有不同的处理方式,阅读 this article 了解更多信息。我将此作为(非常简单的)练习留给 reader.

C 中没有可以将 char 附加到字符串的标准函数。您需要从头开始编写代码。

让我们从这里开始:

char *buffer = malloc(sizeof(char));  // This allocates memory for ONE char
buffer[0] = 'h';                      // So this is fine
buffer[1] = '[=10=]';                     // but this is bad. It writes outside the allocated memory

通过为两个字符分配内存来修复它

char *buffer = malloc(2);  // sizeof(char) is always 1 so no need for it
buffer[0] = 'h';
buffer[1] = '[=11=]';

当你想在字符串中追加一个新的字符时,你也需要为它分配内存。换句话说,您需要增加 buffer 指向的内存大小。为此,您可以使用函数 realloc.

size_t buffer_size = 2;
char *buffer = malloc(buffer_size );
buffer[0] = 'h';
buffer[1] = '[=12=]';

while(...)
{
    char c = read_next_char(); 

    char* tmp = realloc(buffer, buffer_size + 1);
    if (tmp == NULL)
    {
        // realloc failed ! Add error handling here
        ... error handling ...
    }
    buffer = tmp;
    buffer[buffer_size - 1] = c;  // Add the new char
    buffer[buffer_size] = '[=12=]';     // Add the string termination
    ++buffer_size;                  // Update buffer size
}

其他答案可以,但它们很复杂。我建议一个更简单的解决方案。字符串是 char 的数组,其中该字符串的最后一个 char 是一个 '[=13=]' 字节。它后面的数组中可以有更多 char,但它们不是字符串的一部分。

更简单的解决方案是创建一个对 98% 的情况都足够大的数组,用它来存储字符串,当字符串太长时,您可以退出并报错。在需要时更改缓冲区大小是一个不错的功能,但如果您是 C 的新手,则不应从那里开始。

#define BUFFER_SIZE 1024
// init buffer with the first char 'h'
char buffer[BUFFER_SIZE];
buffer[0] = 'h';
buffer[1] = '[=10=]';

// go through input char by char Replace the ... with your condition of the while loop
for(size_t i=1;...;i++) //start at 1 so the 'h' is not overwritten
{
   if(i==BUFFER_SIZE-1) //-1 for the '[=10=]'-Byte
   {
     fputs("Input too long, exit\n",stderr);
     exit(1);
   }
   //Are you sure you don't need error handling for read_next_char()?
   buffer[i] = read_next_char();
   buffer[i+1]='[=10=]'; //End the string with a '[=10=]'-Byte
}