How to Copy C Strings

Proper way to copy C strings

You could use strdup() to return a copy of a C-string, as in:

#include <string.h>

const char *stringA = "foo";
char *stringB = NULL;

stringB = strdup(stringA);
/* ... */
free(stringB);

You could also use strcpy(), but you need to allocate space first, which isn't hard to do but can lead to an overflow error, if not done correctly:

#include <string.h>

const char *stringA = "foo";
char *stringB = NULL;

/* you must add one to cover the byte needed for the terminating null character */
stringB = (char *) malloc( strlen(stringA) + 1 );
strcpy( stringB, stringA );
/* ... */
free(stringB);

If you cannot use strdup(), I would recommend the use of strncpy() instead of strcpy(). The strncpy() function copies up to — and only up to — n bytes, which helps avoid overflow errors. If strlen(stringA) + 1 > n, however, you would need to terminate stringB, yourself. But, generally, you'll know what sizes you need for things:

#include <string.h>

const char *stringA = "foo";
char *stringB = NULL;

/* you must add one to cover the byte needed for the terminating null character */
stringB = (char *) malloc( strlen(stringA) + 1 );
strncpy( stringB, stringA, strlen(stringA) + 1 );
/* ... */
free(stringB);

I think strdup() is cleaner, myself, so I try to use it where working with strings exclusively. I don't know if there are serious downsides to the POSIX/non-POSIX approach, performance-wise, but I am not a C or C++ expert.

Note that I cast the result of malloc() to char *. This is because your question is tagged as a c++ question. In C++, it is required to cast the result from malloc(). In C, however, you would not cast this.

EDIT

There you go, there's one complication: strdup() is not in C or C++. So use strcpy() or strncp() with a pre-sized array or a malloc-ed pointer. It's a good habit to use strncp() instead of strcpy(), wherever you might use that function. It will help reduce the potential for errors.

c - what is the most efficient way to copying a string?

Don't write your own copy loops when you can use a standard function like memcpy (when the length is known) or strcpy (when it isn't).

Modern compilers treat these as "builtin" functions, so for constant sizes can expand them to a few asm instructions instead of actually setting up a call to the library implementation, which would have to branch on the size and so on. So if you're avoiding memcpy because of the overhead of a library function call for a short copy, don't worry, there won't be one if the length is a compile-time constant.

But even in the unknown / runtime-variable length cases, the library functions will usually be an optimized version hand-written in asm that's much faster (especially for medium to large strings) than anything you can do in pure C, especially for strcpy without undefined behaviour from reading past the end of a buffer.

Your first block of code has a compile-time-constant size (you were able to use sizeof instead of strlen). Your copy loop will actually get recognized by modern compilers as a fixed-size copy, and (if large) turned into an actual call to memcpy, otherwise usually optimized similarly.

It doesn't matter how you do the array indexing; optimizing compilers can see through size_t indices or pointers and make good asm for the target platform.
See this and this Q&A for examples of how code actually compiles.
Remember that CPUs run asm, not C directly.

This example is too small and too simplistic to actually be usable as a benchmark, though. See Idiomatic way of performance evaluation?


Your 2nd way is equivalent to strcpy for an implicit-length string. That's slower because it has to search for the terminating 0 byte, if it wasn't known at compile time after inlining and unrolling the loop.

Especially if you do it by hand like this for non-constant strings; modern gcc/clang are unable to auto-vectorize loops there the program can't calculate the trip-count ahead of the first iteration. i.e. they fail at search loops like strlen and strcpy.

If you actually just call strcpy(dst, src), the compiler will either expand it inline in some efficient way, or emit an actual call to the library function. The libc function uses hand-written asm to do it efficiently as it goes, especially on ISAs like x86 where SIMD can help. For example for x86-64, glibc's AVX2 version (https://code.woboq.org/userspace/glibc/sysdeps/x86_64/multiarch/strcpy-avx2.S.html) should be able to copy 32 bytes per clock cycle for medium-sized copies with source and destination hot in cache, on mainstream CPUs like Zen2 and Skylake.

It seems modern GCC/clang do not recognize this pattern as strcpy the way they recognize memcpy-equivalent loops, so if you want efficient copying for unknown-size C strings, you need to use actual strcpy. (Or better, stpcpy to get a pointer to the end, so you know the string length afterwards, allowing you to use explicit-length stuff instead of the next function also having to scan the string for length.)

Writing it yourself with one char at a time will end up using byte load/store instructions, so can go at most 1 byte per clock cycle. (Or close to 2 on Ice Lake, probably bottlenecked on the 5-wide front-end for the load / macro-fused test/jz / store.) So it's a disaster for medium to large copies with runtime-variable source where the compiler can't remove the loop.

(https://agner.org/optimize/ for performance of x86 CPUs. Other architectures are broadly similar, except for how useful SIMD is for strcpy. ISAs without x86's efficient SIMD->integer ability to branch on SIMD compare results may need to use general-purpose integer bithacks like in Why does glibc's strlen need to be so complicated to run quickly? - but note that's glibc's portable C fallback, only used on a few platforms where nobody's written hand-tuned asm.)

@0___________ claims their unrolled char-at-a-time loop is faster than glibc strcpy for strings of 1024 chars, but that's implausible and probably the result of faulty benchmark methodology. (Like compiler optimization defeating the benchmark, or page fault overhead or lazy dynamic linking for libc strcpy.)


Related Q&As:

  • Is memcpy() usually faster than strcpy()? - Yes, although for large copies on x86 strcpy can pretty much keep up; x86 SIMD can efficiently check whole chunks for any zero byte.

  • faster way than memcpy to copy 0-terminated string

  • Idiomatic way of performance evaluation? - microbenchmarking is hard: you need the compiler to optimize the parts that should be optimized, but still repeat the work in your benchmark loop instead of just doing it once.

  • Is it safe to read past the end of a buffer within the same page on x86 and x64? - yes, and all other ISAs where memory protection works in aligned pages. (It's still technically C UB, but safe in asm, so hand-written asm for library functions can 100% safely do this.)

  • Efficiency: arrays vs pointers

  • In C, accessing my array index is faster or accessing by pointer is faster?

Statically copy C-string of variable length

You must have storage space somewhere for the contents of your string copy. There is no magical way to make a copy of something, that doesn't require additional storage.

This however can be on the stack, as apposed to the heap, using a variable-length array.

strlen and strcpy can be used to accomplish this:

void foo(const char *input_str)
{
char temp[strlen(input_str) + 1];
strcpy(temp, str);
/* ... */
}

If your platform does not support VLAs, you must use heap memory. The strdup function is usually available. If it is not, it can be replicated easily with malloc. You must remember to free this memory when you are finished with it.

void foo(const char *input_str)
{
char *temp = strdup(input_str);
/* ... */
free(temp);
}

or

void foo(const char *input_str)
{
char *temp = malloc(strlen(input_str) + 1);
strcpy(temp, input_str);
/* ... */
free(temp);
}

If your platform does not support VLAs, and you really can not use the heap for some reason, the only option left is a buffer of a predetermined maximum length. This is a special case, and should be avoided, if possible, as it creates additional limitations you must keep track of.

#define MAX_FOO_BUFSZ 255

void foo(const char *input_str)
{
char buffer[MAX_FOO_BUFSZ + 1] = { 0 };
strncpy(buffer, input_str, MAX_FOO_BUFSZ);

/* ... */
}

Given a starting and ending indices, how can I copy part of a string in C?

Have you checked strncpy?

char * strncpy ( char * destination, const char * source, size_t num );

You must realize that begin and end actually defines a num of bytes to be copied from one place to another.

C: copy string into list of strings

try this

        printf("Enter name: ");
scanf(" %19[^\n]", name);//add one space and turn 20 to 19 (leave space for '\0')

printf("Enter phone number of %s: ", name);
scanf(" %19[^\n]", phone);

String copy function not copying string properly. What's wrong with my code?

The malloc statement uses sizeof unnecessarily as mentioned in the comments. You also have an error in the assignment of characters to the new string:

s[x] = tolower(st[x]);

You use the same index to the new string s as the old string st. This isn't right as soon as you remove any spaces. So for example indexes 0 through 4 line up between the two strings as you copy hello but then you skip a space at index 5 and then you want to assign the w at st[6] to s[5]. This means you need a separate index to track where you are in the destination string. So you need something like this code, which cleans up malloc(), adds the missing header includes, and introduces a new index for the output string:

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

char *removeSpace(char *st);

int main(void){
char *x = "HeLLO WOrld ";

x = removeSpace(x);
printf("output: %s\n", x);

}

char *removeSpace(char *st)
{
size_t len = strlen(st);
int newStrIdx = 0;
char *s = malloc(len+1);
for (int x = 0; x < len; x++)
{
if (st[x] != ' ')
{
s[newStrIdx++] = tolower(st[x]);
}
}
s[newStrIdx] = '\0';

return s;
}

Oh, and you forgot the null-terminate the output string, which I added at the end.

How can I copy some strings from file to another using c programming

In the end of each line there is a newline character, (\n) you can use that to read line by line and copy only the ones that you want:

FILE* dest = fopen("out.txt", "w+"); // supressed null check for simplicity

char buf[100];

char* char_to_find;

// parse line by line
while (fscanf(ptr, " %99[^\n]", buf) == 1){

char_to_find = buf;

// reach the end of the line
while(*char_to_find){
char_to_find++;
}

//move one back
char_to_find--;

// if it's 5 save, if not move on
if(*char_to_find == '5' && *(char_to_find - 1) == ' '){

fputs(buf, dest);
}
}

Live demo

How to copy a string of std::string type in C++?

You shouldn't use strcpy() to copy a std::string, only use it for C-Style strings.

If you want to copy a to b then just use the = operator.

string a = "text";
string b = "image";
b = a;


Related Topics



Leave a reply



Submit