3

For example:

char s[]="abcde";
    for(int i=0;i<strlen(s);i++)
          cout<<s+i<<endl;

Output:

abcde
bcde
cde
de
e

And this doesn't ruin the char array.

What I want to ask for help is, is there another way we can do that with the std::string class?

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
Nhân Nguyễn
  • 105
  • 1
  • 4
  • 9
  • 4
    use `std::string::substr` – Michał Walenciak Mar 09 '16 at 09:49
  • 3
    You can still use `std::string::c_str() + i`. – Jarod42 Mar 09 '16 at 09:51
  • 3
    Never use a call of `strlen` as condition in a loop while iterating on string. You do extra work, it makes complexity _O(n^2)_ instead of _O(n)_. – αλεχολυτ Mar 09 '16 at 10:04
  • @alexolut: Never use _the same_ call of `strlen`. Microsoft sometimes uses a pattern where a list of strings is represented as one contiguous character array, and the list is terminated by an empty string. The loop you need there is `for(char* s = begin; strlen(s) ; s+=strlen(s)+1)` This is clearly O(n*m) because you have O(n) strings of length O(m). – MSalters Mar 09 '16 at 11:26
  • @MSalters not enough clearly as I see, because of call of `strlen` twice on iteration. – αλεχολυτ Mar 09 '16 at 11:44
  • @alexolut: True, but `O(n*m*2)` is identical to `O(n*m)`. That said, you can optimize it: `size_t len; for(char* s = begin; len = strlen(s) ; s+=len+1)` – MSalters Mar 09 '16 at 11:53
  • @MSalters Agreed. My first sentence was about iterating on string **by symbols**. In your case - that's loop on list of strings by strings. – αλεχολυτ Mar 09 '16 at 12:16

1 Answers1

6

Cheap and nasty way, closest to what you already have: use std::string::c_str()

std::string const s{"abcde"};
char const *c = s.c_str();
for (std::size_t i=0; i<s.size(); ++i)
    std::cout << c+i << '\n';

The more string-like way is to use std::string::substr:

std::string const s{"abcde"};
for (std::size_t i=0; i<s.size(); ++i)
    std::cout << s.substr(i) << '\n';

Note that the second approach does involve allocating memory for the new string every time, but I think here the benefit of clarity (using a function specifically named and designed for what you are trying to do), and avoiding raw pointers (often a cause of confusion for beginners) both outweigh the performance (non-)issue here.


A more modern approach that combines the clarity of using specific C++ components designed for what you want, with avoiding extra allocations, is to use std::experimental::string_view, which is designed to wrap an existing string of characters:

std::string const s{"abcde"};
std::experimental::string_view sv{s};
for (std::size_t i=0; i<s.size(); ++i) {
    std::cout << sv << '\n';
    sv.remove_prefix(1);
}

std::experimental::string_view::remove_prefix does what you might expect: shrinks the view of the string it is wrapping at the front, by the number specified.

string_view is not technically part of The Standard yet, so I don't really recommend it for production use, since you won't get good cross-platform support. But it's quite fun to learn about. You might consider the very similar (not coincidentally) component, boost::string_ref to be production quality.


Also, please reconsider your use of what are often considered bad practices: using namespace std; and endl (those are links to explanations).

Community
  • 1
  • 1
BoBTFish
  • 19,167
  • 3
  • 49
  • 76