Function to shift array elements not working - c++

I have a null terminated array of chars. Also known as a c-string. I have written a function that will shift the elements at each index left, <---- by a given number of indexes. For example, when the char array of "hello world" is passed to the function, with a shiftBy value of 3, it should transform the char array to be: "lo worldhel".
Currently, this function works for all strings that <= 11 elelements. Anything over that and the last three spots in the array don't get shifted. Keep in mind, the very last index is holding the null terminator!
This is a tricky one and I have been stuck for hours. I also can't use any standard functions or vectors, I am stuck with these deprecated arrays and simple loops. So please don't troll with "Why don;t you use blank function"....because trust me, if I could I wouldn't be here.
Here is the code, have at at:
void shiftLeft (char szString[], int size, int shiftBy)
{
if(shiftBy > size){
shiftBy = shiftBy - size;
}
if(size == 1){
//do nothing, do nothing, exit function with no change made to myarray
}
else{
char temp;
//for loop to print the array with indexes moved up (to the left) <-- by 2
for (int i = 0; i <= size-shiftBy; i++)//size = 11
{//EXAMPLE shift by 3 for a c-string of `hello world`
if(i < size-shiftBy){
temp = szString[shiftBy + i];//temp = h
szString[shiftBy + i] = szString[i];//d becomes l
szString[i] = temp;//h becomes l
}
else{//it will run once while i=8
temp = szString[i];//temp = l
szString[i] = szString[i+1];//8th element becomes h
szString[i+1] = szString[size-1];//9th element becomes e
szString[size-1] = temp;//last element becomes l
}
}
}
}

If the only purpose you're trying to accomplish is shifting chars in a terminated string left with rotation (and judging by your sample of "helloworld" resulting in "loworldhel" after a 3-shift, that seems to be the case), you're making this much harder than it needs to be.
The traditional algorithm to do this in O(N) time with no temporary space requirements is to reverse the left-side of the shift, then the entire sequence, then the right side of the shift, all based from the beginning of the sequence. For example, suppose we want to left-shift the following string 3 slots:
1234567890
First, reverse the first shiftBy slots
1234567890
^-^
3214567890
Second, reverse the entire sequence
3214567890
^--------^
0987654123
Finally, reverse the (length-shiftBy) slots:
0987654123
^-----^
4567890123
Using the standard library would make this trivial, but apparently you're prof considers that... cheating. Without using any library apis the above algorithm isn't very hard regardless:
#include <iostream>
void shiftLeft(char sz[], size_t shiftBy)
{
const char *p = sz;
while (*p) ++p;
std::size_t len = p - sz;
if (len > 1 && (shiftBy %= len))
{
char *ends[] = { sz+shiftBy, sz+len, sz+(len - shiftBy) };
for (std::size_t i=0; i<3; ++i)
{
char *start = sz, *end = ends[i];
while (start < --end)
{
char ch = *start;
*start++ = *end;
*end = ch;
}
}
}
}
int main()
{
char sz[] = "1234567890";
std::cout << sz << '\n';
shiftLeft(sz, 11);
std::cout << sz << '\n';
shiftLeft(sz, 4);
std::cout << sz << '\n';
shiftLeft(sz, 1);
std::cout << sz << '\n';
shiftLeft(sz, 20);
std::cout << sz << '\n';
}
Output
1234567890
2345678901
6789012345
7890123456
7890123456
If you're really set on doing this in temp space, so be it, but I cannot possibly fathom why you would do so.
Best of luck.

From azillionmonkeys.com/qed/case8.html
void shiftLeft(char szString[], int size, int shiftBy) {
int c, tmp, v;
if (size <= 0) return;
if (shiftBy < 0 || shiftBy >= size) {
shiftBy %= size;
if (shiftBy < 0) shiftBy += size;
}
if (shiftBy == 0) return;
c = 0;
for (v = 0; c < size; v++) {
int t = v, tp = v + shiftBy;
char tmp = szString[v];
c++;
while (tp != v) {
szString[t] = szString[tp];
t = tp;
tp += shiftBy;
if (tp >= size) tp -= size;
c++;
}
szString[t] = tmp;
}
}

Related

Prevent loop from echoing if another same-value array element has been already echoed in C++

First of all, sorry for the mis-worded title. I couldn't imagine a better way to put it.
The problem I'm facing is as follows: In a part of my program, the program counts occurences of different a-zA-Z letters and then tells how many of each letters can be found in an array. The problem, however, is this:
If I have an array that consists of A;A;F;A;D or anything similar, the output will be this:
A - 3
A - 3
F - 1
A - 3
D - 1
But I am required to make it like this:
A - 3
F - 1
D - 1
I could solve the problem easily, however I can't use an additional array to check what values have been already echoed. I know why it happens, but I don't know a way to solve it without using an additional array.
This is the code snippet (the array simply consists of characters, not worthy of adding it to the snippet):
n is the size of array the user is asked to choose at the start of the program (not included in the snippet).
initburts is the current array member ID that is being compared against all other values.
burts is the counter that is being reset after the loop is done checking a letter and moves onto the next one.
do {
for (i = 0; i < n; i++) {
if (array[initburts] == array[i]) {
burts++;
}
}
cout << "\n\n" << array[initburts] << " - " << burts;
initburts++;
burts = 0;
if (initburts == n) {
isDone = true;
}
}
while (isDone == false);
Do your counting first, then loop over your counts printing the results.
std::map<decltype(array[0]), std::size_t> counts;
std::for_each(std::begin(array), std::end(array), [&counts](auto& item){ ++counts[item]; });
std::for_each(std::begin(counts), std::end(counts), [](auto& pair) { std::cout << "\n\n" << pair.first << " - " pair.second; });
for (i = 0; i < n; i++)
{
// first check if we printed this character already;
// this is the case if the same character occurred
// before the current one:
bool isNew = true;
for (j = 0; j < i; j++)
{
// you find out yourself, do you?
// do not forget to break the loop
// in case of having detected an equal value!
}
if(isNew)
{
// well, now we can count...
unsigned int count = 1;
for(int j = i + 1; j < n; ++j)
count += array[j] == array[i];
// appropriate output...
}
}
That would do the trick and retains the array as is, however is an O(n²) algorithm. More efficient (O(n*log(n))) is sorting the array in advance, then you can just iterate over the array once. Of course, original array sequence gets lost then:
std::sort(array, array + arrayLength);
auto start = array;
for(auto current = array + 1; current != array + arrayLength; ++current)
{
if(*current != *start)
{
auto char = *start;
auto count = current - start;
// output char and count appropriately
}
}
// now we yet lack the final character:
auto char = *start;
auto count = array + arrayLength - start;
// output char and count appropriately
Pointer arithmetic... Quite likely that your teacher gets suspicious if you just copy this code, but it should give you the necessary hints to make up your own variant (use indices instead of pointers...).
I would do it this way.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
string s;
vector<int> capCount(26, 0), smallCount(26, 0);
cout << "Enter the string\n";
cin >> s;
for(int i = 0; i < s.length(); ++i)
{
char c = s.at(i);
if(c >= 'A' && c <= 'Z')
++capCount[(int)c - 65];
if(c >= 'a' && c <= 'z')
++smallCount[(int)c - 97];
}
for(int i = 0; i < 26; ++i)
{
if(capCount[i] > 0)
cout << (char) (i + 65) << ": " << capCount[i] << endl;
if(smallCount[i] > 0)
cout << (char) (i + 97) << ": " << smallCount[i] << endl;
}
}
Note: I have differentiated lower and upper case characters.
Here's is the sample output:
output

Generating all combinations with unknown length

I'm practicing in programming and I generating all combinations in c++. I know how to generate all combination in
certain length
My result is something like that
A A A
A A B
A A C
A B A
A B B
A B C
A C A
A C B
A C C
B A A
.....
and my problem is, I don't know, how to generate all combinations with unknown length. For example I want word length = 5 and program will generate all combination in exactly length 5. How to do it?
A A A A A
A A A A B
A A A A C
A A A B A
.........
(Sorry for my english)
See the link Print all permutations with repetition of characters
The below recursive function in the page, can create last+1 length permutations.
/* The main function that recursively prints all repeated
permutations of the given string. It uses data[] to store all
permutations one by one */
void allLexicographicRecur (char *str, char* data, int last, int index)
{
int i, len = strlen(str);
// One by one fix all characters at the given index and recur for
// the/ subsequent indexes
for ( i=0; i<len; i++ )
{
// Fix the ith character at index and if this is not the last
// index then recursively call for higher indexes
data[index] = str[i] ;
// If this is the last index then print the string stored in
// data[]
if (index == last)
printf("%s\n", data);
else // Recur for higher indexes
allLexicographicRecur (str, data, last, index+1);
}
}
I think this can serve your purpose.
Call allLexicographicRecur with the required (length-1) value for the 'last' parameter.
This is actually nothing more than counting.
If you have the letters A, B, and C, you are counting in base 3.
A is 0, B is 1 and C is 2.
Quick and dirty:
#include <string>
#include <iostream>
int main()
{
for(int i = 0; i < 100; i++) {
const int base = 3;
const char zero_char = 'A';
const size_t length = 5;
std::string out;
for(int n = i; n > 0; ) {
int d = n%base;
out = static_cast<char>(zero_char + d) + out;
n /= base;
}
while(out.length() < length) out = zero_char + out;
std::cout << out << '\n';
}
}
see it live
The possible combinations are baselength, so if you want all combinations for A, B, C with 5 digits, change the limit of the first for loop to 35 ( = 243):
for(int i = 0; i < 243; i++)
You may use something like:
bool increase(const std::string& s, std::vector<std::size_t>& it)
{
for (std::size_t i = 0, size = it.size(); i != size; ++i) {
const std::size_t index = size - 1 - i;
++it[index];
if (it[index] >= s.size()) {
it[index] = 0;
} else {
return true;
}
}
return false;
}
void do_job(const std::string& s,
const std::vector<std::size_t>& it)
{
for (std::size_t i = 0; i != it.size(); ++i) {
std::cout << s[it[i]] << " ";
}
std::cout << std::endl;
}
void cartesian_product(const std::string& s, std::size_t n)
{
std::vector<std::size_t> it(n, 0u);
do {
do_job(s, it);
} while (increase(s, it));
}
Demo

Reverse Array with given sentinel value

FYI: I am new to programming.
I have an arraysize of 10 and the sentinel value is 0.
My original array is [1 2 3] ( user input) but my reverse is [0 0 0 0 0 0 0 3 2 1].
I need help to make my reverse array [3 2 1].
Here is my code:
int temp;
for (int i = 0; i < arraysize/2; i++)
{
temp = array[arraysize-1-i];
array[arraysize - i - 1] = array[i];
array[i] = temp;
}
cout << "The reverse array: ";
for (int i = 0; i < arraysize; i++)
cout << array[i]<< ' ';
cout << endl;
Just use the standard library algorithms
auto end = std::find(std::begin(array),std::end(array),0);
std::reverse(std::begin(array),end);
//And if you only want to print the non-zero values:
size_t effectiveArraySize = end - std::begin(array);
If the fixed size array is not part of your requirement, you should put your user data in a vector that automaticaly grows as large as you need, instead of using an array that might turn out to be too small:
std::vector<int> v;
while(true) {
int t;
cin >> t;
if (t == 0) {
break;
}
v.push_back(t);
}
std::reverse(v.begin(),v.end());
That way, you don't have any sentinel values in your array / vector to begin with.
Note: Using the respective functions from the STL (std::reverse and std::find) is better, I was just guessing that you are bound to implement this on your own.
Step one: Write a proper reverse function. One that takes (a pointer to) the beginning as well as (a pointer to) the end of the range that should be reversed.
Step two: Write a function to find (the first position of) your sentinel in an array (given via beginning and end, again)
Step three: Connect the two: Reverse from the beginning to the position of your sentinel.
Example without templates:
void reverse(int * from, int * to) {
while ((to - from) > 1) {
--to;
int temp = *from;
*from = *to;
*to = temp;
++from;
}
}
int const * find(int const * from,
int const * const to,
int const value) {
while ((from != to) && (*from != value)) {
++from;
}
return from;
}
void reverse_until (int * const from,
int * const to,
int const sentinel) {
int const * const position_sentinel = find(from, to, sentinel);
reverse(from, from + (position_sentinel - from));
// return the sentinel position from this function
// if you want only the reversed part
}
Tested with:
int main() {
int test[10];
for (size_t i = 0; i < 10; ++i) {
test [i] = i + 1;
}
reverse_until (test, test + 10, 6);
copy(test, test + 10, ostream_iterator<int>{cout, " "});
return 0;
}
(live here)
You need to find the actual length of the array, before performing the reverse operation, and then use that length for all further operations.
Like this:
int actualArraySize = 0;
while(actualArraySize < arraysize && array[actualArraySize]!=0)
{
actualArraySize++;
}
int temp;
for (int i = 0; i < actualArraySize/2; i++)
{
temp = array[actualArraySize-1-i];
array[actualArraySize - i - 1] = array[i];
array[i] = temp;
}
cout << "The reverse array: ";
for (int i = 0; i < actualArraySize; i++)
cout << array[i]<< ' ';
cout << endl;
Note that, actualArraySize can be less than or equal to arraysize, but, not more than it, because of the condition in while(actualArraySize < arraysize && array[actualArraySize]!=0), which means that stop when either a 0 is found or the size of the array is reached.

Insert symbol into string C++

I need to insert symbol '+' into string after its each five symbol.
st - the member of class String of type string
int i = 1;
int original_size = st.size;
int count = 0;
int j;
for (j = 0; j < st.size; j++)
{
if (i % 5)
count++;
}
while (st.size < original_size + count)
{
if (i % 5)
{
st.insert(i + 1, 1, '+');
st.size++;
}
i++;
}
return st;
I got an error in this part of code. I think it is connected with conditions of of the while-cycle. Can you help me please how to do this right?
If I've understood you correctly then you want to insert a '+' character every 5 chars in the original string. One way to do this would be to create a temporary string and then reassign the original string:
std::string st("A test string with some chars");
std::string temp;
for (int i = 1; i <= st.size(); ++i)
{
temp += st[i - 1];
if (i % 5 == 0)
{
temp += '+';
}
}
st = temp;
You'll notice I've started the loop at 1, this is to avoid the '+' being inserted on the first iteration (0%5==0).
#AlexB's answer shows how to generate a new string with the resulting text.
That said, if your problem is to perform in-place insertions your code should look similar to this:
std::string st{ "abcdefghijk" };
for(auto i = 4; i != st.size(); i += 5)
st.insert(i+1, 1, '+'); // insert 1 character = '+' at position i
assert(st == "abcde+fghij+k");
std::string InsertEveryNSymbols(const std::string & st, size_t n, char c)
{
const size_t size(st.size());
std::string result;
result.reserve(size + size / n);
for (size_t i(0); i != size; ++i)
{
result.push_back(st[i]);
if (i % n == n - 1)
result.push_back(c);
}
return result;
}
You don't need a loop to calculate the length of the resulting string. It's going to be simply size + size / 5. And doing multiple inserts makes it a quadratic-complexity algorithm when you can just as easily keep it linear.
Nothing no one else has done, but eliminates the string resizing and the modulus and takes advantage of a few new and fun language features.
std::string temp(st.length() + st.length()/5, '\0');
// preallocate string to eliminate need for resizing.
auto loc = temp.begin(); // iterator for temp string
size_t count = 0;
for (char ch: st) // iterate through source string
{
*loc++ = ch;
if (--count == 0) // decrement and test for zero much faster than
// modulus and test for zero
{
*loc++ = '+';
count = 5; // even with this assignment
}
}
st = temp;

remove commas from string

I created a program in C++ that remove commas (,) from a given integer. i.e. 2,00,00 would return 20000. I am not using any new space. Here is the program I created:
void removeCommas(string& str1, int len)
{
int j = 0;
for (int i = 0; i < len; i++)
{
if (str1[i] == ',')
{
continue;
}
else
{
str1[j] = str1[i];
j++;
}
}
str1[j] = '\0';
}
void main()
{
string str1;
getline(cin, str1);
int i = str1.length();
removeCommas(str1, i);
cout << "the new string " << str1 << endl;
}
Here is the result I get:
Input : 2,000,00
String length =8
Output = 200000 0
Length = 8
My question is that why does it show the length has 8 in output and shows the rest of string when I did put a null character. It should show output as 200000 and length has 6.
Let the standard library do the work for you:
#include <algorithm>
str1.erase(std::remove(str1.begin(), str1.end(), ','), str1.end());
If you don't want to modify the original string, that's easy too:
std::string str2(str1.size(), '0');
str2.erase(std::remove_copy(str1.begin(), str1.end(), str2.begin(), ','), str2.end());
You need to do a resize instead at the end.
Contrary to popular belief an std::string CAN contain binary data including 0s. An std::string 's .size() is not related to the string containing a NULL termination.
std::string s("\0\0", 2);
assert(s.size() == 2);
The answer is probably that std::strings aren't NUL-terminated. Instead of setting the end+1'th character to '\0', you should use str.resize(new_length);.
Edit: Also consider that, if your source string has no commas in it, then your '\0' will be written one past the end of the string (which will probably just happen to work, but is incorrect).
The std::srting does not terminate with \0, you are mixing this with char* in C. So you should use resize.
The solution has already been posted by Fred L.
In a "procedural fashion" (without "algorithm")
your program would look like:
void removeStuff(string& str, char character)
{
size_t pos;
while( (pos=str.find(character)) != string::npos )
str.erase(pos, 1);
}
void main()
{
string str1;
getline(cin, str1);
removeStuff(str1, ',');
cout<<"the new string "<<str1<<endl;
}
then.
Regards
rbo
EDIT / Addendum:
In order to adress some efficiency concerns of readers,
I tried to come up with the fastest solution possible.
Of course, this should kick in on string sizes over
about 10^5 characters with some characters to-be-removed
included:
void fastRemoveStuff(string& str, char character)
{
size_t len = str.length();
char *t, *buffer = new char[len];
const char *p, *q;
t = buffer, p = q = str.data();
while( p=(const char*)memchr(q, character, len-(p-q)) ) {
memcpy(t, q, p-q);
t += p-q, q = p+1;
}
if( q-str.data() != len ) {
size_t tail = len - (q-str.data());
memcpy(t, q, tail);
t += tail;
}
str.assign(buffer, t-buffer);
delete [] buffer;
}
void main()
{
string str1 = "56,4,44,55,5,55"; // should be large, 10^6 is good
// getline(cin, str1);
cout<<"the old string " << str1 << endl;
fastRemoveStuff(str1, ',');
cout<<"the new string " << str1 << endl;
}
My own procedural version:
#include <string>
#include <cassert>
using namespace std;
string Remove( const string & s, char c ) {
string r;
r.reserve( s.size() );
for ( unsigned int i = 0; i < s.size(); i++ ) {
if ( s[i] != c ) {
r += s[i];
}
}
return r;
}
int main() {
assert( Remove( "Foo,Bar,Zod", ',' ) == "FooBarZod" );
}
Here is the program:
void main()
{
int i ;
char n[20] ;
clrscr() ;
printf("Enter a number. ") ;
gets(n) ;
printf("Number without comma is:") ;
for(i=0 ; n[i]!='\0' ; i++)
if(n[i] != ',')
putchar(n[i]) ;
getch();
}
For detailed description you can refer this blog: http://tutorialsschool.com/c-programming/c-programs/remove-comma-from-string.php
The same has been discussed in this post: How to remove commas from a string in C
Well, if youre planing to read from a file using c++. I found a method, while I dont think thats the best method though, but after I came to these forums to search for help before, I think its time to contribute with my effort aswell.
Look, here is the catch, what I'm going to present you is part of the source code of the map editor Im building on right now, that map editor obviously has the purpose to create maps for a 2D RPG game, the same style as the classic Pokemon games for example. But this code was more towards the development of the world map editor.
`int strStartPos = 0;
int strSize = 0;
int arrayPointInfoDepth = 0;
for (int x = 0; x < (m_wMapWidth / (TileSize / 2)); x++) {
for (int y = 0; y < (m_wMapHeight / (TileSize / 2)); y++) {
if (ss >> str) {
for (int strIterator = 0; strIterator < str.length(); strIterator++) {
if (str[strIterator] == ',') {`
Here we need to define the size of the string we want to extract after the previous comma and before the next comma
`strSize = strIterator - strStartPos;`
And here, we do the actual transformation, we give to the vector that is a 3D vector btw the string we want to extract at that moment
`m_wMapPointInfo[x][y][arrayPointInfoDepth] = str.substr(strStartPos, strSize);`
And here, we just define that starting position for the next small piece of the string we want to extract, so the +1 means that after the comma we just passed
strStartPos = strIterator + 1;
Here, well since my vector has only 6 postions that is defined by WorldMapPointInfos we need to increment the third dimension of the array and finally do a check point where if the info has arrived the number 6 then break the loop
arrayPointInfoDepth++;
if (arrayPointInfoDepth == WorldMapPointInfos) {
strStartPos = 0;
arrayPointInfoDepth = 0;
break;
}
}
}
}
}
}
Either way on my code, think abt that the vector is just a string, thats all you need to know, hope this helps though :/
Full view:
int strStartPos = 0;
int strSize = 0;
int arrayPointInfoDepth = 0;
for (int x = 0; x < (m_wMapWidth / (TileSize / 2)); x++) {
for (int y = 0; y < (m_wMapHeight / (TileSize / 2)); y++) {
if (ss >> str) {
for (int strIterator = 0; strIterator < str.length(); strIterator++) {
if (str[strIterator] == ',') {
strSize = strIterator - strStartPos;
m_wMapPointInfo[x][y][arrayPointInfoDepth] = str.substr(strStartPos, strSize);
strStartPos = strIterator + 1;
arrayPointInfoDepth++;
if (arrayPointInfoDepth == WorldMapPointInfos) {
strStartPos = 0;
arrayPointInfoDepth = 0;
break;
}
}
}
}
}
}