63

I have a string:

char * someString;

If I want the first five letters of this string and want to set it to otherString, how would I do it?

tadman
  • 208,517
  • 23
  • 234
  • 262
SuperString
  • 21,593
  • 37
  • 91
  • 122
  • 4
    someString is not a string, it is a pointer to a string of chars. Also, chars are not necessarily letters. You need to know what a string is before moving letters around. –  Jan 22 '10 at 01:51
  • Depending on your need its better to declare a char array of size 6 for otherstring( 5 + one byte for '\0'). This way you don't have to care about memory leaks incase you forget to free otherstring after using it. – HeretoLearn Jan 22 '10 at 02:20
  • I’m voting to close this question because it teaches new users the wrong way to ask, even voting should be disabled. – Wolf Jan 26 '21 at 09:04
  • Warning: this old question comes with a flood of very bad answers teaching dangerous or incorrect/buggy practice. Some will not even compile. I advise the reader to avoid this post, or otherwise scroll down to the answer I just posted. I also strongly recommend to down vote all the horrible answers, particularly the ones with outright bugs and compiler errors. – Lundin Mar 10 '22 at 07:46

13 Answers13

70
#include <string.h>
...
char otherString[6]; // note 6, not 5, there's one there for the null terminator
...
strncpy(otherString, someString, 5);
otherString[5] = '\0'; // place the null terminator
Velizar Hristov
  • 662
  • 2
  • 10
  • 23
pib
  • 3,293
  • 18
  • 15
  • 4
    Or `otherString[5] = (char)0;` If you want to be picky about it. Char is an integer type, so compilers won't (or shouldn't) complain about just assigning a raw integer to it. – pib Jan 24 '10 at 17:47
  • 2
    Thank you for reminding me to place the terminating char in single quotes insted of double quotes. – Seagull Sep 12 '17 at 14:49
  • 2
    @pib Unclear about [comment](https://stackoverflow.com/questions/2114377/strings-in-c-how-to-get-substring#comment2066644_2114388). Both `otherString[5] = '\0';` and `otherString[5] = 0;`, in C, are assigning an `int` with a value of 0 to a `char`. So how does `(char)` help in `otherString[5] = (char)0;`? – chux - Reinstate Monica Jul 24 '18 at 17:48
  • 2
    This is bad advise. `strncpy` is a dangerous function that should never be used, because way too many people fail to understand how it works. In this case `strncpy` may or may not null terminate the string by itself, depending on the length. It's fickle, unreliable and not originally intended to be used with null terminated strings at all. See [Is strcpy dangerous and what should be used instead?](https://software.codidact.com/posts/281518) – Lundin Mar 10 '22 at 07:24
10
char* someString = "abcdedgh";
char* otherString = 0;

otherString = (char*)malloc(5+1);
memcpy(otherString,someString,5);
otherString[5] = 0;

UPDATE:
Tip: A good way to understand definitions is called the right-left rule (some links at the end):

Start reading from identifier and say aloud => "someString is..."
Now go to right of someString (statement has ended with a semicolon, nothing to say).
Now go left of identifier (* is encountered) => so say "...a pointer to...".
Now go to left of "*" (the keyword char is found) => say "..char".
Done!

So char* someString; => "someString is a pointer to char".

Since a pointer simply points to a certain memory address, it can also be used as the "starting point" for an "array" of characters.

That works with anything .. give it a go:

char* s[2]; //=> s is an array of two pointers to char
char** someThing; //=> someThing is a pointer to a pointer to char.
//Note: We look in the brackets first, and then move outward
char (* s)[2]; //=> s is a pointer to an array of two char

Some links: How to interpret complex C/C++ declarations and How To Read C Declarations

alk
  • 69,737
  • 10
  • 105
  • 255
Liao
  • 1,225
  • 3
  • 14
  • 22
  • 1
    I think you should try compiling `char *[] someThing;` and `char []* someThing;`. You want `char *someThing[];` and `char (*someThing)[];` respectively. And that breaks your algorithm to understand definitions. – Alok Singhal Jan 22 '10 at 02:50
  • //Thanks, you're right about the bad syntax..fixed the code. However, the algorithm still stands, see the update. – Liao Jan 22 '10 at 23:41
  • Don't forget to free after malloc – ShihabSoft Mar 08 '16 at 20:04
  • `memcpy(someString, otherString, 5);` may have undefined behavior if `someString` has fewer than 4 characters. It works in your example because the source string is longer, but the behavior is not fully defined for small source strings. – chqrlie Jul 16 '22 at 12:10
10

Generalized:

char* subString (const char* input, int offset, int len, char* dest)
{
  int input_len = strlen (input);

  if (offset + len > input_len)
  {
     return NULL;
  }

  strncpy (dest, input + offset, len);
  return dest;
}

char dest[80];
const char* source = "hello world";

if (subString (source, 0, 5, dest))
{
  printf ("%s\n", dest);
}
Dan Olson
  • 22,849
  • 4
  • 42
  • 56
  • 2
    it will better if add '\0' at dest[len+1] no? – JoseLinares Mar 05 '16 at 11:35
  • 1
    There is a subtle bug here; you need to change if(offset + len) to if(offset) otherwise the last characters of the string will never be read; for example: http://cpp.sh/955ib – Blaskovicz Jul 03 '20 at 02:46
4

You'll need to allocate memory for the new string otherString. In general for a substring of length n, something like this may work for you (don't forget to do bounds checking...)

char *subString(char *someString, int n) 
{
   char *new = malloc(sizeof(char)*(n+1));
   strncpy(new, someString, n);
   new[n] = '\0';
   return new;
}

This will return a substring of the first n characters of someString. Make sure you free the memory when you are done with it using free().

svlasov
  • 9,923
  • 2
  • 38
  • 39
Neal
  • 6,722
  • 4
  • 38
  • 31
4

You can use snprintf to get a substring of a char array with precision:

#include <stdio.h>

int main()
{
    const char source[] = "This is a string array";
    char dest[17];

    // get first 16 characters using precision
    snprintf(dest, sizeof(dest), "%.16s", source);

    // print substring
    puts(dest);
} // end main

Output:

This is a string

Note:

For further information see printf man page.

angelvmx
  • 61
  • 5
  • Not sure what is the cost of this, but the fact of using only one single standard Lib to do this operation, it's kinda remarkable – PYK Jul 04 '18 at 06:33
1

You can treat C strings like pointers. So when you declare:

char str[10];

str can be used as a pointer. So if you want to copy just a portion of the string you can use:

char str1[24] = "This is a simple string.";
char str2[6];
strncpy(str1 + 10, str2,6);

This will copy 6 characters from the str1 array into str2 starting at the 11th element.

1

I had not seen this post until now, the present collection of answers form an orgy of bad advise and compiler errors, only a few recommending memcpy are correct. Basically the answer to the question is:

someString = allocated_memory; // statically or dynamically
memcpy(someString, otherString, 5);
someString[5] = '\0';

This assuming that we know that otherString is at least 5 characters long, then this is the correct answer, period. memcpy is faster and safer than strncpy and there is no confusion about whether memcpy null terminates the string or not - it doesn't, so we definitely have to append the null termination manually.


The main problem here is that strncpy is a very dangerous function that should not be used for any purpose. The function was never intended to be used for null terminated strings and it's presence in the C standard is a mistake. See Is strcpy dangerous and what should be used instead?, I will quote some relevant parts from that post for convenience:

Somewhere at the time when Microsoft flagged strcpy as obsolete and dangerous, some other misguided rumour started. This nasty rumour said that strncpy should be used as a safer version of strcpy. Since it takes the size as parameter and it's already part of the C standard lib, so it's portable. This seemed very convenient - spread the word, forget about non-standard strcpy_s, lets use strncpy! No, this is not a good idea...

Looking at the history of strncpy, it goes back to the very earliest days of Unix, where several string formats co-existed. Something called "fixed width strings" existed - they were not null terminated but came with a fixed size stored together with the string. One of the things Dennis Ritchie (the inventor of the C language) wished to avoid when creating C, was to store the size together with arrays [The Development of the C Language, Dennis M. Ritchie]. Likely in the same spirit as this, the "fixed width strings" were getting phased out over time, in favour for null terminated ones.

The function used to copy these old fixed width strings was named strncpy. This is the sole purpose that it was created for. It has no relation to strcpy. In particular it was never intended to be some more secure version - computer program security wasn't even invented when these functions were made.

Somehow strncpy still made it into the first C standard in 1989. A whole lot of highly questionable functions did - the reason was always backwards compatibility. We can also read the story about strncpy in the C99 rationale 7.21.2.4:

The strncpy function strncpy was initially introduced into the C library to deal with fixed-length name fields in structures such as directory entries. Such fields are not used in the same way as strings: the trailing null is unnecessary for a maximum-length field, and setting trailing bytes for shorter 5 names to null assures efficient field-wise comparisons. strncpy is not by origin a “bounded strcpy,” and the Committee preferred to recognize existing practice rather than alter the function to better suit it to such use.

The Codidact link also contains some examples showing how strncpy will fail to terminate a copied string.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • 1
    While I agree with your assessment of the answers posted for this question, your recommendation to use `memcpy` is not perfect either: `memcpy(someString, otherString, 5);` may have undefined behavior if `someString` has fewer than 4 characters. There is a simple one liner for this problem: `sprintf(someString, "%.5s", otherString)` but it feels like going grocery shopping with a Sherman tank. – chqrlie Jul 16 '22 at 11:48
0

I think it's easy way... but I don't know how I can pass the result variable directly then I create a local char array as temp and return it.

char* substr(char *buff, uint8_t start,uint8_t len, char* substr)
{
    strncpy(substr, buff+start, len);
    substr[len] = 0;
    return substr;
}
-1
strncpy(otherString, someString, 5);

Don't forget to allocate memory for otherString.

Colin
  • 10,447
  • 11
  • 46
  • 54
  • 3
    Note that this may result in an unterminated string (if `someString` contains five or more characters). – strager Jan 22 '10 at 02:28
-1
#include <stdio.h>
#include <string.h>

int main ()
{
        char someString[]="abcdedgh";
        char otherString[]="00000";
        memcpy (otherString, someString, 5);
        printf ("someString: %s\notherString: %s\n", someString, otherString);
        return 0;
}

You will not need stdio.h if you don't use the printf statement and putting constants in all but the smallest programs is bad form and should be avoided.

gavaletz
  • 337
  • 2
  • 6
  • You need to set otherString[5] = '\0' as well – Bill Forster Jan 22 '10 at 02:20
  • otherstring after the memcpy is not a valid C string as its not null terminated. After the memcpy you need to add otherstring[5] = '\0'; – HeretoLearn Jan 22 '10 at 02:22
  • Or you can memset(otherstring,'\0',sizeof(otherstring)); before using it. – HeretoLearn Jan 22 '10 at 02:24
  • That is true, and this illuminates a good issue. Code flexibility should not come at the expense of simplicity. It could ba as simple as char otherString[]="00000"; and thus the null terminating character is a non-issue. The use of '0' instead of '\0' was what prompted my response in the first place, and then I went and forgot it myself... – gavaletz Jan 22 '10 at 04:51
  • This is plain incorrect since you don't null terminate the string nor allocate room for the null terminator. – Lundin Mar 10 '22 at 07:42
-1

Doing it all in two fell swoops:

char *otherString = strncpy((char*)malloc(6), someString);
otherString[5] = 0;
Steve Emmerson
  • 7,702
  • 5
  • 33
  • 59
  • @pm100 I happen to agree but no one else was, so I figured it was implied. – Steve Emmerson Jan 23 '10 at 04:08
  • Bad advise to use strncpy, see [Is strcpy dangerous and what should be used instead?](https://software.codidact.com/posts/281518). Additionally you failed to use it correctly so this code will not compile. – Lundin Mar 10 '22 at 07:28
  • Missing 3rd argument for `strncpy` – chqrlie Jul 16 '22 at 12:13
-1
char largeSrt[] = "123456789-123";  // original string

char * substr;
substr = strchr(largeSrt, '-');     // we save the new string "-123"
int substringLength = strlen(largeSrt) - strlen(substr); // 13-4=9 (bigger string size) - (new string size) 

char *newStr = malloc(sizeof(char) * substringLength + 1);// keep memory free to new string
strncpy(newStr, largeSrt, substringLength); // copy only 9 characters 
newStr[substringLength] = '\0'; // close the new string with final character

printf("newStr=%s\n", newStr);

free(newStr);   // you free the memory 
Cristian
  • 548
  • 6
  • 8
-2

Try this code:

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

char* substr(const char *src, unsigned int start, unsigned int end);

int main(void)
{
    char *text = "The test string is here";
    char *subtext = substr(text,9,14);

    printf("The original string is: %s\n",text);
    printf("Substring is: %s",subtext);

    return 0;
}

char* substr(const char *src, unsigned int start, unsigned int end)
{
    unsigned int subtext_len = end-start+2;
    char *subtext = malloc(sizeof(char)*subtext_len);

    strncpy(subtext,&src[start],subtext_len-1);
    subtext[subtext_len-1] = '\0';

    return subtext;
}
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Mar 10 '22 at 12:00