将一个字符数组中的字符追加到字符指针中。

6

好的,我是一名通常编写Java/C++代码的人,最近开始学习C语言。我正在编写一个词法分析器,但我无法忍受C语言中字符串的工作方式,因为我无法执行字符串算术运算。所以这是我的问题:

char* buffer = "";
char* line = "hello, world";

int i;
for (i = 0; i < strlen(line); i++) {
    buffer += line[i];
}

我该如何在C语言中实现这个功能?由于上面的代码不是有效的C语言,所以我该怎样做类似的操作呢?基本上,我正在遍历一个字符串 line ,并尝试将每个字符追加到 buffer 字符串中。


如果我正在循环遍历该行,那么我如何通过strcpy传递单个字符,而该函数需要(char,const char)类型的参数? - metro-man
1
@user3839220:你正在尝试将字符串复制到“buffer”。所以只需用一个“strcpy()”调用替换整个“for”循环即可。 - sampathsris
1
@Krumia 嗯,这只是我实际正在做的一个较小的示例。我想能够将字符追加到char*中,而不是复制两个字符串。 - metro-man
如果将buffer声明为指向字符串字面值的指针,则无法修改它。 - McLovin
@al-Acme:重复的是一个[tag:c++]问题。而这个是[tag:c]。 - sampathsris
显示剩余2条评论
7个回答

2

首先,缓冲区需要具有或超过被复制到其中的数据的长度。

char a[length], b[] = "string";

然后将字符复制到缓冲区。

int i = 0;
while (i < length && b[i] != '\0') { a[i] = b[i]; i++; }
a[i] = '\0';

如果需要,您可以反转顺序,只需从两个字符串中最小长度值开始使用i,并递减该值而不是递增。您还可以使用堆,如其他人建议的那样,以任意或可变的length值为基准。此外,您可以使用指针改变代码片段(为了更好地理解发生了什么):

int i = 0;
char *j = a, *k = b;
while (j - a < length && *k) { *(j++) =  *(k++); }
*j = '\0';

请务必查找 memcpy;并且不要忘记空终止符(糟糕)。


b[i] != '\0' 和 a[i] = '\0'; - chouaib

2

C中的字符串字面量是不可变的。修改一个字符串字面量会导致未定义行为

如果您使用一个足够大的char数组(即缓冲区)来容纳字符,则仍然可以修改其内容:

#include <stdio.h>

int main(void) {


    char * line = "hello, world";
    char buffer[32]; // ok, this array is big enough for our operation

    int i;
    for (i = 0; i < strlen(line) + 1; i++) 
    {
        buffer[i] = line[i];
    }

    printf("buffer : %s", buffer);

    return 0;
}

1
#include <string.h>

//...

char *line = "hello, world";
char *buffer = ( char * ) malloc( strlen( line ) + 1 );

strcpy( buffer, line );

虽然在 C 语言中字符串字面值的类型是非 const 数组,但最好使用带有 const 限定符的字符串字面值来声明指针:

const char *line = "hello, world";

在C/C++中,字符串字面量是不可变的。
如果您想要追加字符,则代码可以如下所示(每行的每个字符都在循环中附加到缓冲区)。
#include <string.h>

//...

char *line = "hello, world";
char *buffer = ( char * ) malloc( strlen( line ) + 1 );

buffer[0] = '\0';
char *p = Buffer;

for ( size_t i = 0; i < strlen( line ); i++ )
{
    *p++ = line[i];
    *p = '\0';
}

一般的方法是找到指向终止零的指针,将其替换为目标字符,然后移动指针并添加新的终止零。源缓冲区应足够大,以容纳一个以上的字符。

0

使用snprintf进行附加是最好的选择

包含stdio.h头文件

#include <stdio.h>

那么

char* buffer;
char line[] = "hello, world";

// Initialise the pointer to an empty string
snprintf(buffer, 1, "%s", "");

for (i = 0; i < strlen(line); ++i) {
    snprintf(buffer, sizeof line[i], "%s%s", buffer, line[i]);
}

根据你所编写的代码,它与你所提出的问题是不同的。 你可以使用 strtok 函数来分割 line。 但我希望我的回答能够澄清这个问题。


0

如果你想要将一个单独的字符附加到在堆上分配的字符串中,这里是一种方法:

size_t length = strlen(buffer);
char *newbuffer = realloc(buffer, length + 2);
if (newbuffer) {  // realloc succeeded
  buffer = newbuffer;
  buffer[length] = newcharacter;
  buffer[length + 1] = '\0';
}
else {  // realloc failed
  // TODO handle error...
  free(buffer);  // for example
}

然而,在循环中重复执行此操作是低效的,因为您将在(实质上)相同的字符串上重复调用strlen(),并重新分配缓冲区以适应每次一个字符。

如果您想更加聪明地重新分配内存,请将缓冲区的当前分配容量与其中的字符串长度分别保持跟踪 - 如果您了解C ++,请考虑std :: string对象的“大小”和其“容量”的差异 - 并且当需要重新分配时,将缓冲区的大小乘以比例因子(例如将其加倍),而不是加1,以便重新分配的次数为O(log n),而不是O(n)。

这是一个好的字符串类在C ++中会做的事情。在C中,您可能需要将此缓冲区管理内容移动到自己的模块中。


这是我尝试过的,但每次运行可执行文件时似乎总是挂起了? - metro-man
我还没有看到你的代码,所以无法告诉你为什么它会卡住。请使用调试器和/或提出另一个问题,并提供更多关于该问题的细节。 - Wyzard
不知道如何将代码放在这里的部分,所以我将编辑我的帖子。 - metro-man
不要在人们已经回答原问题后,将此问题用于提出另一个问题。请发布另一个问题。 - Wyzard
每90分钟才能发布一次,我就自己想办法吧 :p - metro-man

0

最简单的解决方案,缺乏任何上下文,是执行以下操作:

char buffer[ strlen(line) + 1 ];
strcpy(buffer, line);

你可能习惯在Java中使用指针来存储所有内容(因为在Java中,非原始类型实际上更像是共享指针)。但在C语言中不一定需要这样做,而且这样做可能会很麻烦。
也许你可以考虑在C语言中使用计数字符串对象,其中字符串对象拥有它自己的数据。编写struct my_string { char *data; size_t length; }以及创建、销毁、复制和任何其他所需操作的函数,例如追加一个字符或检查长度。(将接口与实现分开!) 这个类的一个有用的补充是让它分配比length多1个字节,这样你就可以有一个空结束符函数,并且可以将其传递给期望只读C风格字符串的函数。
唯一真正需要注意的问题是,在进行复制操作时记得调用函数,而不是允许结构分配发生。(当然,您可以使用结构赋值进行移动操作!)

0

asprintf函数非常有用,可以用于构建字符串,在基于GNU(Linux)或大多数*BSD系统上可用。您可以执行以下操作:

char *buffer;
if (asprintf(&buffer, "%s: adding some stuff %d - %s", str1, number, str2) < 0) {
    fprintf(stderr, "Oops -- out of memory\n");
    exit(1); }
printf("created the string \"%s\"\n", buffer);
free(buffer);  /* done with it */

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接