append a character from an array to a char pointer
Asked Answered
S

7

6

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. 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? Since the code above isn't valid C, how can I do something like that? Basically I'm looping though a string line, and I'm trying to append each character to the buffer string.

Stralka answered 15/7, 2014 at 3:45 Comment(7)
Well if I'm looping through the line, how do I pass a single character through strcpy which takes (char*, const char*)?Stralka
@user3839220: What you are trying to do is copy the string to buffer. So just replace your entire for loop with an strcpy() call.Caves
possible duplicate of Create a modifiable string literal in C++Figurative
@Krumia Well, this is a smaller example of what I'm actually doing. I want to be able to append characters to a char*, not copy two strings.Stralka
You won't be able to modify buffer if it's declared as a pointer to a string literal.Pecan
@al-Acme: The duplicate is a c++ question. Whereas this is cCaves
I guess i should have looked up this one Modifying String LiteralFigurative
S
2

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. You can also use the heap, as others have suggested, ordinate towards an arbitrary or changing value of 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; and don't forget null terminators (oops).

Settles answered 15/7, 2014 at 4:1 Comment(1)
b[i] != '\0' and a[i] = '\0';Phobos
C
2

string literals are immutable in C. Modifying one causes Undefined Behavior.

If you use a char array (your buffer) big enough to hold your characters, you can still modify its content :

#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;
}
Curnin answered 15/7, 2014 at 4:2 Comment(0)
E
1
#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:

const char *line = "hello, world";

String literals in C/C++ are immutable.

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.

Ellon answered 15/7, 2014 at 3:56 Comment(0)
A
0

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.

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 (e.g. double it) instead of adding 1, so that the number of reallocations is O(log n) instead of O(n).

This is the sort of thing that a good string class would do in C++. In C, you'll probably want to move this buffer-management stuff into its own module.

Altonaltona answered 15/7, 2014 at 4:8 Comment(5)
This is what I've tried, but it always seems to hang when I run the executable?Stralka
I haven't seen your code so I can't tell you why it hangs. Use a debugger and/or ask another question with more details about that problem.Altonaltona
No idea how to put code in this section here, so I'll edit my post.Stralka
No, don't repurpose this question to ask a different question after people have already written answers to the original one. Just post another question.Altonaltona
Can only post every 90 minutes, just figure it out on my own :pStralka
B
0

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). However you don't necessarily have to do this in C and it can be a pain if you do.

Maybe a good idea given your background would be to use a counted string object in C, where the string object owns its data. Write 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.

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!)

Brickbat answered 15/7, 2014 at 4:40 Comment(0)
L
0

The asprintf function is very useful for building strings, and is available on GNU-based systems (Linux), or most *BSD based systems. 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 */
Lammas answered 15/7, 2014 at 5:30 Comment(0)
M
0

Appending is best done with snprintf

Include the stdio.h header

#include <stdio.h>

then

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]);
}

As you have started the code you have there is different from the question you are asking. You could have split the line with strtok though. But I hope my answer clarifies it.

Munmro answered 25/10, 2022 at 12:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.