简体   繁体   English

将数组中的字符附加到字符指针

[英]append a character from an array to a char pointer

Ok, so I'm a person who usually writes Java/C++, and I've just started getting into writing C. I'm currently writing a lexical analyser, and I can't stand how strings work in C, since I can't perform string arithmetic.好的,所以我是一个通常会编写 Java/C++ 的人,而且我刚刚开始编写 C。我目前正在编写一个词法分析器,我无法忍受字符串在 C 中的工作方式,因为我可以'不执行字符串算术。 So here's my question:所以这是我的问题:

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

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

How can I do that in C?我怎样才能在 C 中做到这一点? Since the code above isn't valid C, how can I do something like that?由于上面的代码不是有效的 C,我该怎么做呢? Basically I'm looping though a string line , and I'm trying to append each character to the buffer string.基本上我正在循环一个字符串line ,并且我试图将每个字符附加到buffer字符串。

First off the buffer needs to have or exceed the length of the data being copied to it.首先,缓冲区需要具有或超过复制到它的数据的长度。

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

Then the characters are copied to the buffer.然后将字符复制到缓冲区。

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

You can reverse the order if you need to, just start i at the smallest length value among the two strings, and decrement the value instead of increment.如果需要,您可以颠倒顺序,只需从两个字符串中最小的长度值开始i ,然后递减该值而不是递增。 You can also use the heap, as others have suggested, ordinate towards an arbitrary or changing value of length .您还可以使用堆,正如其他人所建议的那样,将length为任意或变化的值。 Furthermore, you can change up the snippet with pointers (and to give you a better idea of what is happening):此外,您可以使用指针更改代码段(并让您更好地了解正在发生的事情):

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

Make sure to look up memcpy ;确保查找memcpy and don't forget null terminators (oops).并且不要忘记空终止符(哎呀)。

string literals are immutable in C. Modifying one causes Undefined Behavior .字符串文字在 C 中是不可变的。修改一个会导致Undefined Behavior

If you use a char array (your buffer) big enough to hold your characters, you can still modify its content :如果您使用足够大的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;
}
#include <string.h>

//...

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

strcpy( buffer, line );

Though in C string literals have types of non-const arrays it is better to declare pointers initialized by string literals with qualifier const:尽管在 C 字符串文字中有非常量数组的类型,但最好用限定符 const 声明由字符串文字初始化的指针:

const char *line = "hello, world";

String literals in C/C++ are immutable. C/C++ 中的字符串文字是不可变的。

If you want to append characters then the code can look the following way (each character of line is appended to buffer in a loop)如果要附加字符,则代码可以如下所示(行的每个字符都附加到循环中的缓冲区)

#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';
}

The general approach is that you find the pointer to the terminating zero substitute it for the target character advance the pointer and appenf the new terminating zero.一般方法是找到指向终止零的指针,将其替换为目标字符,使指针前进并附加新的终止零。 The source buffer shall be large enough to accomodate one more character.源缓冲区应足够大以容纳多一个字符。

If you want to append a single character to a string allocated on the heap, here's one way to do it:如果要将单个字符附加到在堆上分配的字符串,可以使用以下一种方法:

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
}

However, this is inefficient to do repeatedly in a loop, because you'll be repeatedly calling strlen() on (essentially) the same string, and reallocating the buffer to fit one more character each time.但是,在循环中重复执行此操作效率低下,因为您将(基本上)对同一个字符串重复调用strlen() ,并每次重新分配缓冲区以容纳一个字符。

If you want to be smarter about your reallocations, keep track of the buffer's current allocated capacity separately from the length of the string within it — if you know C++, think of the difference between a std::string object's "size" and its "capacity" — and when it's necessary to reallocate, multiply the buffer's size by a scaling factor (eg double it) instead of adding 1, so that the number of reallocations is O(log n) instead of O(n).如果您想更明智地重新分配,请分别跟踪缓冲区当前分配的容量和其中的字符串长度——如果您了解 C++,请考虑std::string对象的“大小”与其“大小”之间的区别容量”——当需要重新分配时,将缓冲区的大小乘以一个比例因子(例如加倍)而不是加 1,这样重新分配的次数是 O(log n) 而不是 O(n)。

This is the sort of thing that a good string class would do in C++.这是一个好的字符串类在 C++ 中会做的事情。 In C, you'll probably want to move this buffer-management stuff into its own module.在 C 中,您可能希望将此缓冲区管理内容移动到其自己的模块中。

The simplest solution, lacking any context, is to do:没有任何上下文的最简单的解决方案是:

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

You may be used to using pointers for everything in Java (since non-primitive types in Java are actually more like shared pointers than anything else).您可能习惯于对 Java 中的所有内容使用指针(因为 Java 中的非原始类型实际上更像是共享指针而不是其他任何东西)。 However you don't necessarily have to do this in C and it can be a pain if you do.但是,您不一定必须在 C 中执行此操作,如果这样做可能会很痛苦。

Maybe a good idea given your background would be to use a counted string object in C, where the string object owns its data.鉴于您的背景,也许一个好主意是在 C 中使用计数的字符串对象,其中字符串对象拥有其数据。 Write struct my_string { char *data; size_t length; }struct my_string { char *data; size_t length; } struct my_string { char *data; size_t length; } struct my_string { char *data; size_t length; } . struct my_string { char *data; size_t length; } . Write functions for creating, destroying, duplicating, and any other operation you need such as appending a character, or checking the length.编写用于创建、销毁、复制和任何其他您需要的操作(例如附加字符或检查长度)的函数。 (Separate interface from implementation!) A useful addition to this would be to make it allocate 1 more byte than length , so that you can have a function which null-terminates and allows it to be passed to a function that expects a read-only C-style string. (将接口与实现分开!)对此的一个有用补充是使它比length多分配 1 个字节,这样您就可以拥有一个以空值终止的函数,并允许将其传递给需要只读的函数C 风格的字符串。

The only real pitfall here is to remember to call a function when you are doing a copy operation, instead of allowing structure assignment to happen.这里唯一真正的陷阱是记住在执行复制操作时调用函数,而不是允许结构赋值发生。 (You can use structure assignment for a move operation of course!) (当然,您可以将结构分配用于移动操作!)

The asprintf function is very useful for building strings, and is available on GNU-based systems (Linux), or most *BSD based systems. asprintf函数对于构建字符串非常有用,可用于基于 GNU 的系统 (Linux) 或大多数基于 *BSD 的系统。 You can do things like:您可以执行以下操作:

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 */

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM