Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating C substrings: looping with assignment operator VS strncopy, which is better?

This might be somewhat pointless, but I'm curious what you guys think about it. I'm iterating over a string with pointers and want to pull a short substring out of it (placing the substring into a pre-allocated temporary array). Are there any reasons to use assignment over strncopy, or vice-versa? I.e.

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

int main()
{   char orig[]  = "Hello. I am looking for Molly.";

    /* Strings to store the copies
     * Pretend that strings had some prior value, ensure null-termination */
    char cpy1[4] = "huh\0";
    char cpy2[4] = "huh\0";

    /* Pointer to simulate iteration over a string */
    char *startptr = orig + 2;
    int length = 3;
    int i;

    /* Using strncopy */
    strncpy(cpy1, startptr, length);

    /* Using assignment operator */
    for (i = 0; i < length; i++)
    {   cpy2[i] = *(startptr + i); 
    }   

    /* Display Results */
    printf("strncpy result:\n");
    printf("%s\n\n", cpy1);
    printf("loop result:\n");
    printf("%s\n", cpy2);
}   

It seems to me that strncopy is both less typing and more easily readable, but I've seen people advocate looping instead. Is there a difference? Does it even matter? Assume that this is for small values of i (0 < i < 5), and null-termination is assured.

Refs: Strings in c, how to get subString, How to get substring in C, Difference between strncpy and memcpy?

like image 883
surfreak Avatar asked Feb 20 '23 06:02

surfreak


2 Answers

strncpy(char * dst, char *src, size_t len) has two peculiar properties:

  • if (strlen(src) >= len) : the resulting string will not be nul-terminated.
  • if (strlen(src) < len) : the end of the string will be filled/padded with '\0'.

The first property will force you to actually check if (strlen(src) >= len) and act appropiately. (or brutally set the final character to nul with dst[len-1] = '\0';, like @Gilles does above) The other property is not particular dangerous, but can spill a lot of cycles. Imagine:

char buff[10000];
strncpy(buff, "Hello!", sizeof buff);

which touches 10000 bytes, where only 7 need to be touched.

My advice:

  • A: if you know the sizes, just do memcpy(dst,src,len); dst[len] = 0;
  • B: if you don't know the sizes, get them somehow (using strlen and/or sizeof and/or the allocated size for dynamically allocced memory). Then: goto A above.

Since for safe operation the strncpy() version already needs to know the sizes, (and the checks on them!), the memcpy() version is not more complex or more dangerous than the strncpy() version. (technically it is even marginally faster; because memcpy() does not have to check for the '\0' byte)

like image 89
wildplasser Avatar answered Apr 06 '23 17:04

wildplasser


While this may seem counter-intuitive, there are more optimized ways to copy a string than by using the assignment operator in a loop. For instance, IA-32 provides the REP prefix for MOVS, STOS, CMPS etc for string handling, and these can be much faster than a loop that copies one char at a time. The implementation of strncpy or strcpy may choose to use such hardware-optimized code to achieve better performance.

like image 25
Nathan Fellman Avatar answered Apr 06 '23 18:04

Nathan Fellman