8

I have a string:

str1 = "abcabcabc";

How can I remove the first character? I would like the end result to be:

str1 = "bcabcabc";
Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
hkvega
  • 305
  • 3
  • 8
  • 12

7 Answers7

22

If you have a character pointer to a string like:

char *s = "This is my string";

then you can just do s++.

If you have a character array, your best bet may be to have a pointer to that array as well:

char s[] = "This is my string";
char *ps = s;

then you can do ps++ and make sure you use ps rather than s.

If you don't want to have a separate pointer to your array then you can use memmove to copy the data:

memmove (s, s+1, strlen (s+1) + 1); // or just strlen (s)

though none of those will work for an initially empty string so you'll have to check that first. Also keep in mind it's not advisable to attempt modifying string literals in this way (or any way, really) since it's undefined as to whether that's allowed.

Another solution is to simply code up a loop:

for (char *ps = s; *ps != '\0'; ps++)
    *ps = *(ps+1);
*ps = '\0';

This will work for all strings, empty or otherwise.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • 1
    Thanks to you, half of my nerves have been ripped out. :) – Mateen Ulhaq Apr 19 '11 at 06:09
  • 2
    Just one comment. Keep the original pointer if the space for the string is malloc'ed, otherwise there won't be a way to free that space. If the space was hard-coded, then of course no problem. +1 on the recursive beast. :-) – Stephen Chung Apr 19 '11 at 07:11
  • Not exactly sure at the moment... but shouldn't `memmove (s, s+1, strlen (s+1));` be `memmove (s, s+1, strlen (s-1));`? – mozzbozz Jun 16 '15 at 11:57
  • 1
    @mozzbozz, no, you may be thinking of `strlen (s) - 1` which would be correct, equivalent to `strlen (s + 1)` except for the degenerate case where `s[0] == 0`. The expression `strlen (s - 1)` is not the same thing. – paxdiablo Jun 16 '15 at 13:06
  • 1
    @mozzbozz: however, your comment led me to a flaw where I didn't copy the final NUL, so thanks for that, I've fixed it. – paxdiablo Jun 16 '15 at 13:26
  • Ahh yes. That's exactly what I've read: `stlen(s) + 1` - normally, I don't use whitespaces between the function names and the paramters list - that might have irritated me. You're totally right :) C pointer etc. can be handy but when it comes to string handling, it's freaking error prone :[] – mozzbozz Jun 16 '15 at 22:12
6

Pointer tricks (zero-cost):

char* s = "abcd";
char* substr = s + 1;
// substr == "bcd"

Or:

char s[] = "abcd";
char* substr = s + 1;
// substr == "bcd"

In-place via memmove:

char s[] = "abcd";
char* substr = s + 1;
memmove(s, substr, strlen(substr) + 1);
// s == "bcd"

Notice that we must use char[] rather than char*, which would refer to read-only memory, as described here. Furthermore, one should not use strcpy in-place because the src and dest must not overlap for strcpy.


Into a new string via strcpy:

char* src = "abcd";
char* substr = src + 1;
char dest[strlen(substr) + 1];
strcpy(dest, substr);
// dest == "bcd"

Into a new string via C++'s std::string::substr:

std::string src = "abcd";
std::string dest = src.substr(1);
// dest == "bcd"

Into a new string via C++'s std::copy:

std::string src = "abcd";
std::string dest;
std::copy(src.begin() + 1, src.end(), std::back_inserter(dest));
// dest == "bcd"

There's a couple dozen other ways (particularly when including C++), but I'll stop here. :)

Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
  • This suffers from three flaws (one per section). (1) You cannot increment a character _array,_ only a pointer. (2) This one creates a _new_ string, though that's probably fixable by copying back to the original afterwards. (3) Your C++ solution is probably right (I can't comment on that) but it's hardly useful for a C question :-) – paxdiablo Apr 19 '11 at 04:50
  • @paxdiablo (1) I fixed it, then unfixed it because I couldn't remember why I fixed it. :) (2) Does it look OK now? (3) Yeah, I like C++. :) – Mateen Ulhaq Apr 19 '11 at 05:21
  • that whole 3-line `if` bit could be replaced with `strcpy(str2, &(str1[1]));`, no `pstr1` required, and the `sizeof` (in the `if`) should probably be `strlen`. – paxdiablo Apr 19 '11 at 05:25
  • I really like the strcpy method, is there a way to use that to remove not only the first letter but also the last letter? – Cheetaiean Jan 24 '20 at 16:29
  • 1
    @Cheetaiean You can use [`strncpy`](http://www.cplusplus.com/reference/cstring/strncpy/). – Mateen Ulhaq Jan 24 '20 at 16:36
1
#include <stdio.h>
#include <conio.h>
main(){
   char a[10];
   int i;
   gets(a);

   for (i = 0; a[i] != '\0'; i++) {
      a[i] = a[i + 1];
   }

   printf("\n");
   puts(a);
   getch();
}
Adi
  • 5,089
  • 6
  • 33
  • 47
1

If you really meant to say

char str1 [] = "abcabcabc";

Then the easiest thing is

str1 = &str1[1];

If you want to modify the actual data, then you have to just move everything up one position. You can use a loop for that or memmove(). A recursive function is overkill.

If you really meant C++ and you're using the string object then you can use

str1 = str1.substr(1);
Adam
  • 16,808
  • 7
  • 52
  • 98
  • The problem is not in the decaying (which _does_ happen), the problem is in trying to asign to a non-pointer. – paxdiablo Apr 19 '11 at 04:40
  • It works if the str1 is declared as `char* str1`. You're right, if you declare `char str1[]` then it won't work. But it's not clear what the OP is using. – Adam Apr 19 '11 at 04:42
  • @Adam What happens if &str1 is passed to a function that expects `char **` and is incremented there? Does it cause a crash when `str1` goes out of scope? – dashesy May 19 '12 at 18:02
  • @dashesy if str1 is declared as `char* str1` then you can't pass it to a function that accepts a `char **` anyway. A crash happens (hopefully) when you access memory that has been freed. That's unrelated to the above. If `str1` goes out of scope then any statement involving `str1` is a compiler error. – Adam May 22 '12 at 22:09
  • @Adam- I meant passing &str1 when `char str1[]="abcabcabc";` – dashesy May 23 '12 at 05:25
  • @dashesy that's a pointer to a pointer, so if you increment it you'll be incrementing by `sizeof(char*)` (i.e. 4 or 8) instead of `sizeof(char)` (i.e. 1). In other words, you're implying to the compiler that you have an array of pointers to strings, not an array of characters. Note that `&str1` is not the same as `str1`, so you'll get different results anyway. But you could still do `(*arg)++` if `arg` is that `char**` argument – Adam May 24 '12 at 16:05
1

Here is one way to do it:

int index = 0; //index to cull
memmove( &word[ index ] , &word[ index +1], strlen( word ) - index) ;
Shreesh
  • 677
  • 5
  • 15
1

Well as far as i know if you are worried about memory allocation you have to copy (str1+1) into a new string that you personally allocate memory for, then free the first pointer. The really simple way to do it would be to just increment str1 with str1++; That would make it point one character farther than it used to and give you the desired result with just a line of code.

Tincu Gabi
  • 11
  • 1
0
#include <stdio.h>
int main() {
  char a[15] = "!Hello world!";
  sprintf(a,"%s",a+1);
  printf("%s",a);
}
KITISH
  • 18
  • 3
  • This code exhibits undefined behaviour. From [cppreference](https://en.cppreference.com/w/c/io/fprintf): *The C standard and POSIX specify that the behavior of sprintf and its variants is undefined when an argument overlaps with the destination buffer.* – Adrian Mole Sep 27 '22 at 17:44