0

I have this piece of code:

int i = 0;
char s[12];
strcpy(s,"abracadabra");
cout << strlen(s);
while(i < strlen(s))
{
    if (s[i]=='a') strcpy(s+i, s+i+1);
    else i++;
}
cout << " " << s;

But I can't understand why the output is brcdbr.

I thought that s+i means s[n+i] or something like that?

Can someone explain to me how this works?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
paokv
  • 13
  • 1
  • 8
    It's undefined behavior, because `strcpy` has undefined behavior if the source & destination ranges overlap. As they do here. It appears the intent is to remove all `'a'` characters from the `char` array, in an inefficient manner. – Eljay Feb 24 '21 at 17:07
  • Related: [Result of calling strcpy is different than expected](https://stackoverflow.com/questions/27546706/result-of-calling-strcpy-is-different-than-expected). – dxiv Feb 24 '21 at 17:10
  • 2
    `s+i` is like `&s[i]`, and `s+i+1` is like `&s[i+1]`. For user specified overload `operator[]` on a user type, those similarities may not apply. – Eljay Feb 24 '21 at 17:17

2 Answers2

0

In your terminal type man strcpy

char *strcpy(char *dest, const char *src);

The strcpy() function copies the string pointed to by src, including the terminating null byte ('\0'), to the buffer pointed to by dest. The strings may not overlap, and the destination string dest must be large enough to receive the copy. Beware of buffer overruns! (See BUGS.)

So you are copying all bytes from your string,

  • from src: index i + 1 (the next letter after 'a') to '\0'
  • to dest: index i (letter 'a') to '\0'

NB: As stated in the comments it is a very inefficient way and undefined behavior to get rid of the 'a', but I guess you came here for the explanation about s+i, it means &s[i] or even &i[s].

Read more about "Pointer arithmetic"

If you want an efficient way take a look at this post

Antonin GAVREL
  • 9,682
  • 8
  • 54
  • 81
  • *"The strings may not overlap"* this is important. As Eljay mentioned in the comments this is undefined behavior. – Kevin Feb 24 '21 at 17:32
  • Yes I bolded it. However his question is mostly about pointer arithmetic and not so much about the very bad usage of strcpy even though it is worth pointing out. – Antonin GAVREL Feb 24 '21 at 17:33
0

Can someone explain to me how this works?

it doesn't work, the behavior of the program is undefined. Nothing meaningful can be said about the outcome (even if it looks correct in some specific case).

For example, here on godbolt the output is not brcdbr but brcdrr.

That's because it's illegal to invoke strcpy with overlapping source and destination pointers:

C11 §7.24.2.3 The strcpy function

The strcpy function copies the string pointed to by s2 (including the terminating null character) into the array pointed to by s1. If copying takes place between objects that overlap, the behavior is undefined.

(note: C++ inherits C rules for C standard library functions)

Anyway, if you just wanted to know the intention behind strcpy(s+i, s+i+1), in C++ expressions an array automatically decays to a pointer. So char s[12] becomes char* s. Then the expression s+i becomes pointer arithmetic - taking an address of ith element pointed-to by s. It is equivalent to writing &s[i], i.e. taking an address of ith element in s. The same applies to s+i+1 - it evaluates to a pointer to the i+1th element in s. The intention of the strcpy call was to copy the remainder of the string after a to the memory are starting at a, i.e. to shift the remaining characters forward by one, thus overwriting the a.

A better way in C++ would be to use std::string and the erase-remove idiom to remove the characters a from the string:

#include <iostream>
#include <algorithm>
#include <string>

int main() {
    std::string s = "abracadabra";
    s.erase(std::remove(s.begin(), s.end(), 'a'), s.end());
    std::cout << s << std::endl;
}

Prints:

brcdbr
rustyx
  • 80,671
  • 25
  • 200
  • 267