1

I want to extract, edit and re-concatenate a string that contains an integer. How does this get done?

char str_test[] = "CAT ";
int count = 10;
//(1) something here to combine str_test and count stored in some variable
char str_new[] = ????;
//(2) something else here to extract the 10 and +1? 
//such that if I print str_new, it gives me "CAT 11"

????

Kenneth
  • 11
  • 2
  • 3
    `char str_new[10]; snprintf(str_new, sizeof str_new, "%s%d", str_test, count);` – pmg Mar 28 '21 at 08:32
  • Any thoughts on 2? Once i get the str_new, how would I be able to auto detect the size of the int and make a +1 to it and add back/ – Kenneth Mar 28 '21 at 08:35
  • 1
    You might consider storing the string and int separately in a struct and generating the concatenated string on demand. – Retired Ninja Mar 28 '21 at 08:42
  • `extract the 10 and +1? //such that if I print str_new, it gives me "CAT 10"` what `+1`? – KamilCuk Mar 28 '21 at 08:50
  • [How to convert unsigned long to string](https://stackoverflow.com/q/2709713/4279) – jfs Mar 28 '21 at 09:13
  • Your string doesn't contain a number (It contains `"CAT "`) Can you elaborate? I cannot help you until we both have the same interpretation of your string. – Luis Colorado Mar 29 '21 at 05:47

1 Answers1

1

You can use sprintf to write a formatted number to a string, and you can use snprintf to find out how many characters are required.

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


/*  Return a newly allocated string containing String followed by Number
    converted to decimal.  The caller is responsible for freeing the memory.
*/
static char *ConcatenateIntToString(const char *String, int Number)
{
    //  Get the number of non-null characters in String.
    size_t Length = strlen(String);

    /*  Allocate space for:
            the characters in String,
            the characters needed to format Number with "%d", and
            a terminating null byte.
    */
    char *Result = malloc(
        Length
        + snprintf(NULL, 0, "%d", Number)
        + 1);

    //  Test whether the allocation succeeded.
    if (!Result)
    {
        fprintf(stderr, "Error, unable to allocate memory.\n");
        exit(EXIT_FAILURE);
    }

    //  Copy the characters from String.
    memcpy(Result, String, Length);

    //  Append the formatted number and a null terminator.
    sprintf(Result + Length, "%d", Number);

    //  Return the new string.
    return Result;
}


int main(void)
{
    char *NewString = ConcatenateIntToString("CAT ", 11);
    printf("The new string is %s.\n", NewString);
    free(NewString);
}
Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • Rather than computing `strlen` and using memcpy/sprintf, it seems like it would be cleaner to compute the size needed for `Result` with `snprintf(NULL, 0, "%s%d", String, Number)` and use `"%s%d"` with `snprintf` to write Result in one go. – William Pursell Mar 28 '21 at 10:57
  • @WilliamPursell: Timing on my system for 100 million repetitions of calling `ConcatenateIntToString` and `free` shows 20 seconds with the code in the answer, 25 seconds using `%s%d` instead of `strlen` and `memcpy`. – Eric Postpischil Mar 28 '21 at 13:45
  • @EricPostpischil, Well, your function is quite inefficient, and can be responsible of 20 of the 25 seconds you spent calling it 100 million times. This should make the approach of William Pursell far more efficient than yours. Indeed, you make 100 million allocations of the same string, which could be handled by an external buffer. If you are to try something 100million times to do some benchmark, don't hide its results in a bunch of unrelated code to appear as very efficient coding. – Luis Colorado Mar 29 '21 at 05:52
  • @LuisColorado: What are you talking about? William Pursell did not suggest not using memory allocation, and it is necessary if the caller does not provide a buffer. My test compared my method to the alternative Purnell suggested and demonstrated the alternative was slower. – Eric Postpischil Mar 29 '21 at 07:24
  • but your memory allocation is indeed involved in the test you did (calling the function 100 million times) and you are basing the whole execution to justify only part of the task (which is avoiding strlen and using snprintf) your test is not significative to explain that. – Luis Colorado Mar 31 '21 at 06:03
  • by the way, suggesting the user to provide a buffer himself, should be an interesting approach that can save 100 million allocations also :) Probably you can save 5 seconds with the approach suggested by william, and 19s more saving 100 million calls to malloc (and free, which is something you probably do in your test, and you have not accounted for) – Luis Colorado Mar 31 '21 at 06:04
  • @LuisColorado: If a person and a box A weigh 200 pounds and the same person and box B weigh 210 pounds, which box weighs more? The fact that memory allocation is included in the test is no more significant to which code is faster than the weight of the person is to which box weighs more. Because the weight of the person is the same in each test, we know box B weighs more even though we do not know what its weight is. Similarly, because the memory allocation is the same in each test, we know the first method is faster even though we do not know how fast it is. – Eric Postpischil Mar 31 '21 at 10:05
  • @LuisColorado: In any case, timing just the `size_t Length = strlen(String); memcpy(Result, String, Length); sprintf(Result + Length, "%d", Number);` alone takes 6.9 seconds (for 100,000,000 repetitions), while `sprintf(Result, "%s%d", String, Number);` takes 9.7 seconds. – Eric Postpischil Mar 31 '21 at 10:15