How can input a word and reverse the output of it. I made a function to calculate the length of the word and from here I have to reverse the word depending on the length of it.
How can I do that?
#include<iostream>
using std::cout;
using std::endl;
using std::cin;
int LengthOfString( const char *); // declaring prototype for length of the string
int reverse(const char []);
int main()
{
char string1[100];
cout<<"Enter a string: ";
cin>>string1;
cout<<"Length of string is "<<LengthOfString(string1);
system("PAUSE");
return 0;
}
int LengthOfString( const char *x)
{
int index;
for(index = 0; *x!='\0';x++,index++);
return index;
}
int reverse(const char y[])
{
/* my attempted loop, its not right i know.
a[] = *index; // length of the word
for(int i=0; i<=index/2; i++)
for(j=0; j == length, j--) */
}
This wheel has already been invented, and exists in the standard library.
#include <iostream>
#include <string>
#include <algorithm>
int main()
{
std::string word;
std::cout << "Enter a word: ";
std::cin >> word;
std::reverse(word.begin(), word.end());
std::cout << "Reverse: " << word << std::endl;
return 0;
}
To understand exactly what's going on here, there are a few things that you must cover first:
data structures (classes)
containers
iterators
I hope you already know what a class is. In case you're still in introductory stuff, a class is basically a user defined collection of state and behavior. The author can choose to restrict access to the state or behavior of a class for a variety of reasons. In the case of std::string, the standard library string class, all of the state is hidden and only behavior is accessible.
The string class is a container that contains characters. There are numerous other container classes, each of which with different strengths and weaknesses. The string class contains a sequence of characters with a strict order. Other containers exist, such as std::set, std::vector, std::list, and others. std::string bears a passing resemblance to std::vector, and is a distant cousin of std::list. Each collection behaves differently and is suited for different things.
You might think you need to understand how the string class stores its data in order to reverse it, but you don't. This is where iterators come in. std::string owns a typedef, std::string::iterator, which is a special object which stores the location of a single element in a string. std::reverse is a library function which takes 2 iterators and repeatedly swaps their contents and moves them towards each other. This looks like this as it's happening:
v v <-- positions of iterators (start at the start, end at the end)
ABC <-- initial state
v v <-- the end iterator moved back
ABC
v v
CBA <-- the iterators swapped their values
vv <-- the begin iterator moved forward
CBA
V <-- the end iterator moved back; both iterators are in the same place
CBA <-- therefore, we're done, the string is reversed
One thing about iterators is they're kind of like pointers. In fact, you can pass pointers to some functions that expect iterators because they behave syntactically the same. Therefore, you should be able to write your own reverse function that uses pointers that basically does the same thing this did, except with char *s.
Here's some pseudocode that you should be able to write the function with (I won't write it out completely because it's homework):
namespace BaidNation
{
void reverse(char *begin, char *end)
{
loop forever
{
if (end equals begin):
done;
move end backwards;
if (end equals begin):
done;
swap end's and begin's characters;
move begin forwards;
}
}
}
Keep in mind that BaidNation::reverse (as well as std::reverse) expects for end the iterator that references the element AFTER the end of the collection, not the one that references the last element. How does it then make sense to use this?
Your LengthOfString function returns the number of non-null characters in a string. Since arrays are zero-indexed, we know that, like any other array, if we check string1 + LengthOfString(string1), we'll get a pointer to the character after the end which is, for once, exactly what we want.
Thus, we can use this to reverse the string:
BaidNation::reverse(string1, string1 + LengthOfString(string1));
If you have to use exactly the signature earlier, you can adapt this design into the other one:
int reverse(const char str[])
{
char *start = str, *end = str + LengthOfString(str);
BaidNation::reverse(start, end);
}
Based on the fact that the return type of your prototype function is int, it looks to me like you want to do an in-place reversal of a string. You first need to find out how long the string is (although you computed that before, you didn't pass the result to this function), then swap elements until you get to the middle. To make this work you need to pass, not a const char[], but just a char* (indicating that you will be changing the content):
int reverse(char* y)
{
int ii, n;
n = LengthOfString(y); // "no built in functions - otherwise, use strlen()
for(ii=0; ii<n/2;ii++) {
char temp;
temp = y[ii];
y[ii] = y[n - ii - 1];
y[n - ii] = temp;
}
}
Declare a new char* of the same length, and then loop as follows -
for(int i=0;i<stringLength;i++){
newString[i]=oldString[stringLength-i];
}
return newString;
Also you might want to consider using the String class instead of char*.
Related
struct Word {
string wordName; //loses its value
vector<string> contents; //irrelevant for the question
int numContents = 0; //maintains its value
};
vector<Word*> wordMsgs;
int main()
{
vector<string> result;
result.push_back("wordName");
result.push_back("shouldEnterIf");
Word curr;
//New Word
if (result[1] != "") {
Word w;
w.numContents = 10; //just a testing #, suppose to represent size of vector
wordMsgs.push_back(&w);
w.wordName = result[0]; //name of Word
//here w.wordName and (*wordMsgs[0]).wordName display the same string; result[0]
curr = w;
}
//here curr.wordName displays result[0] but (*wordMsgs[0]).wordName doesn't. However, (*wordMsgs[0]).numContents returns 10 as expected
}
}
So I have a vector of struct references, assuming the push_back() method for vectors only pushes a copy to the end of the vector. I create an instance of my Word struct and put that reference into my vector, wordMsgs. I then edit the struct it is pointing too and then my string variable is lost upon leaving the if statement! However, my int variable never loses its value.
I don't understand because I used pointers (and I'm in C++ so I thought strings were a-okay) and I wouldn't think this is a local variable issue...
The variable w in:
if (...) {
Word w;
wordMsgs.push_back(&w);
...
}
Is allocated on the stack inside the scope of the if statement.
You are then adding its address to your vector of pointers.
Once outside the if statement, this variable is deallocated and the value at that address is no longer "solid", so you essentially have a "garbage address" in that vector.
From here onward, the behavior of your program is mostly unpredictable...
Here is a minimal example of what is going wrong in your code:
#include <string>
#include <vector>
#include <iostream>
int main() {
std::vector<string*> words; // why pointers?
if (true) { // scope starts here
std::string word = "muh";
words.push_back(&word); // dont do that !!
} // scope ends here
std::cout << *words.back();
}
By the time you access the string by dereferencing the pointer, the string is long gone, because word is destroyed when it goes outof scope. Dereferencing the pointer is undefined behaviour. You shouldnt have raw pointers in the vector when you dont need to. You probably wanted something like this:
#include <string>
#include <vector>
#include <iostream>
int main() {
std::vector<string> words;
if (true) {
std::string word = "muh";
words.push_back(word); // vector stores a copy ! and manages lifetime of its elements
}
std::cout << words.back();
}
You have a vector of pointers, not refrences. When you push back the adress of the locally defined struct Wors w by using &w you will lose that data directly when you go out of the if statement. You need to allocate and deallocate memory for the vector. Best to either just push objects in the vector or use a smart pointer.
I'm trying to implement a function that deletes a character from a string wherever the current index is. Below is a skeleton of what I have so far. I'm trying to rotate the character I want to remove to the end of the string then replace it with a null terminator. The code I have below does not seem to actually rotate buffer because the output I'm getting is "wor" instead of the expected output "wrd".
int main() {
char buffer[]="word";
int currIndex=2;
int endIndex=strlen(buffer);
currIndex--;
endIndex--;
rotate(buffer+currIndex,
buffer+1,
buffer+strlen(buffer));
buffer[endIndex]='\0';
cout << buffer << endl;
return 0;
}
This doesn't attempt to answer the question being asked, but rather solve the underlying problem: Removing a single character from a string.
The solution is a simple application of the std::string::erase class member:
#include <string>
#include <iostream>
int main() {
std::string word{ "word" };
std::string::size_type currIndex{ 2 };
word.erase( currIndex, 1 );
std::cout << word << std::endl;
}
Using a std::string makes things way easier because I don't have to think about pointers:
std::string buffer="word";
rotate(buffer.begin()+1, buffer.begin()+2, buffer.end());
buffer.resize(buffer.size()-1);
Demo
Alternatively, we can stick with a c-style array:
char buffer[]="word";
rotate(buffer+1, buffer+2, buffer+4);
buffer[3] = '\0';
Demo2
std::rotate accepts 3 arguments:
template< class ForwardIt >
ForwardIt rotate( ForwardIt first, ForwardIt n_first, ForwardIt last );
first is the first element in the range you want to left rotate.
nfirst is the element you want to be at the start of the range after you've rotated (this tells the algorithm how many times to left rotate, effectively)
last is the last element in the range you want to rotate.
Your code:
char buffer[]="word";
int currIndex=2;
int endIndex=strlen(buffer);
currIndex--;
endIndex--;
rotate(buffer+currIndex,
buffer+1,
buffer+strlen(buffer));
buffer[endIndex]='\0';
Was actually really close. You just got the second argument wrong. It should have been
rotate(buffer+currIndex,
buffer+2,
buffer+strlen(buffer));
buffer[endIndex]='\0';
But the code was admittedly a bit confusing written with the increments and decrements.
I am trying to find the difference in my code when I use std::find.
For my test code. I made a Vector called Test
std::vector<const char*> Test;
To test the find function, I filled the Test vector with dummy data by using push_back function
Test.push_back("F_S");
Test.push_back("FC");
Test.push_back("ID");
Test.push_back("CD");
Test.push_back("CT");
Test.push_back("DS");
Test.push_back("CR");
Test.push_back("5K_2");
Test.push_back("10K_5");
Test.push_back("10K_1");
Test.push_back("10K_2");
Test.push_back("10K_3");
Test.push_back("10K_4");
Test.push_back("10K_5");
What I want to do with the find function is to go through the Test and see if there are any repeated data. The first time a encounter the data, I will save it to a vector called Unique_Data.
std::vector<const char*> Unique_Data;
So for the 14 data points above, only 13 will be saved because 10K_5 repeated.
The Code I am using looks like this
for(int i = 0; i < Test.size(); i++)
{
if( Unique_Data.empty())
{
Unique_Data.push_back(Test[i]);
}
else if (std::find(Unique_Data.begin(), Unique_Data.end(), Test[i]) != Unique_Data.end())
{
// Move on to next index
}
else
{
Unique_Data.push_back(Test[i]);
}
}
The problem I am having is when I am using the dummy data. I am getting a correct answer for Unique_Data.
However, if I save the actual data into the Test vector which are saved in linked list. I get that they are all unique.
The code looks like this
p_curr = List.p_root;
while(p_curr != NULL)
{
// id starts from 0
if(atoi(p_curr->id) == 14) break;
Test.push_back(p_curr->Descriptor);
p_curr = p_curr->p_next;
}
I tested with the same 14 data. They are all const char* types. However, when I used the linked list data. The find function thinks all the data is unique.
Can anyone tell me what is wrong with this?
Using C-style strings is a bit tricky, they are just a pointer, and pointers are compared by identity. Two C strings with the same sequence of characters, but different addresses will compare different.
const char first[] = "Hi";
const char second[] = "Hi";
assert(first == second); // will fail!
There are two solutions to this problem. The simple one is using std::string in your container, as std::string will provide value comparisons. The alternative is to pass a comparison functor to std::find as a last argument. But this will still leave the problem of managing the lifetime of the const char*-s stored in the vector.
This is a pointers problem. You're not storing strings in your array, you're storing the memory address of the data in the string.
This strange behaviour is probably because in your example case you have literal strings that cannot be changed, so the compiler is optimising the storage, and when two strings are the same then it stores the same address for all strings that have the same text.
In your real data example, you have a bunch of strings that hold the same data, but each of these strings lives at a different memory address, so the find function is saying that all strings have a different address.
In summary, your find function is looking at the memory address of the string, not the data (text) in the string. If you use std::strings then this problem will disappear.
I would highly recommend using strings, as performance is going to be more than good enough and they eliminate a vast number of problems.
As David Rodriguez mentions in his answer, you're only comparing pointers, and not the contents of the strings themselves. Your solution will work as is if you were storing std::strings instead of char const *. With the latter, you need to resort to std::find_if and a predicate that calls strcmp to determine whether the strings are identical.
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
int main()
{
std::vector<const char*> Test;
Test.push_back("F_S");
Test.push_back("FC");
Test.push_back("ID");
Test.push_back("CD");
Test.push_back("CT");
Test.push_back("DS");
Test.push_back("CR");
Test.push_back("5K_2");
Test.push_back("10K_5");
Test.push_back("10K_1");
Test.push_back("10K_2");
Test.push_back("10K_3");
Test.push_back("10K_4");
Test.push_back("10K_5");
std::vector<const char*> Unique_Data;
for(auto const& s1 : Test) {
if(std::find_i(Unique_Data.cbegin(), Unique_Data.cend(),
[&](const char *s2) { return std::strcmp(s1, s2) == 0; })
== Unique_Data.cend()) {
Unique_Data.push_back(s1);
}
}
for(auto const& s : Unique_Data) {
std::cout << s << '\n';
}
}
Here's a live example
How to sum number of strings in string array in which is not explicit defined how many elements it takes?
string str[] = { "astring", "bstring", "cstring", "dstring", "zstring" };
Need to find out how many elements array have?
template< typename T, size_t N >
/*constexpr*/ size_t size( T(&arr)[N]) )
{
return N;
}
constexpr if available (C++11) will allow you to use the return value for static (compile time) usage as a size of another array.
If str[] is statically defined (as shown), then this will work:
const size_t numElements = sizeof(str) / sizeof(str[0]);
If it's dynamically created, then you are going to need a marker to signal the last element (0 is being typically used if it's an array of pointers). Either that or the caller tells you how many elements there are (also common).
In addition to the methods already listed in other answers, another way to do this might be to add a guard value to the end of the array, such as an empty string. You can then iterate through the array until you hit the guard value.
Personally, I'd probably use C++11 and
std::vector<std::string> la = { "foo", "bar", "baz" };
so you can just query la.size() to get what you wanted... at runtime, anyway. Unfortunately, i don't see a way to use this trick with std::array, so it isn't a perfect alternative.
one way using pointers to count the elements of the array:
#include <iostream>
using namespace std;
int main() {
string str[] = { "astring", "bstring", "cstring", "dstring", "zstring" };
cout << ((&str)[1] - str); // 5
cout << endl;
return 0;
}
output:
5
I usually use a separate variable for tracking array size.
String str[] = { "astring", "bstring", "cstring", "dstring", "zstring" };
int strNum = 5;
And then if I need to reference any of the strings, I can just call it as such:
String foo = str[strNum-1];
And any time I update the array in a loop, i simply use strNum as the index to start writing new strings to, and then place a strNum++ within the loop immediately after each new string.
I have an array of strings which need to be taken into a map. Since the array size is variable, I need a 2d vector to obtain the string character-wise. i need both formats of storage for operations i perform on them. Here's my attemp..gives errors in (EDIT:)run time.
#include "stdafx.h"
#include<iostream>
#include<string>
#include<fstream>
#include<map>
#include<vector>
#include<algorithm>
#include<iterator>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
using namespace std;
std::map<int,string>col;
std::map<int,string>row;
std::map<int,string>::iterator p;
std::map<int,string>d1;
std::map<int,string>d2;
int main()
{
int i=0,r=0;
string s;
ifstream ip;
ip.open("a.in");
ofstream op;
op.open("a_out.in");
ip>>s;
const int c= s.length();
ip.seekg(0,std::ios::beg);
do {
ip>>s;row.insert(make_pair(r,s));
r++;
}while(s.length()==c);
p=row.find(--r);
row.erase(p);
p = row.begin();
while(p!=row.end())
{
cout<<(p->first)<<","<<(p->second)<<"\n";
p++;
}
vector<vector<char>>matrix(r,vector<char>(c));
rep(i,0,r){
int k=0;rep(j,0,c)(p->second).copy(&matrix[i][j],1,k++);
}
rep(i,0,r)
rep(j,0,c)
cout<<matrix[i][j];
return 0;
}
It looks like the problem occurs after you print out the map, before you copy the strings into the vector. You need two things:
while(p!=row.end())
{
cout<<(p->first)<<","<<(p->second)<<"\n";
p++;
}
p = row.begin(); // Must reset iterator!
vector<vector<char>>matrix(r,vector<char>(c));
rep(i,0,r){
int k=0;
rep(j,0,c)(p->second).copy(&matrix[i][j],1,k++);
++p; // Must advance the iterator.
}
That should fix the map/set iterator not dereferencable, as in the doubly nested for loop you referenced an invalid iterator (p was set to row.end()).
Edit:
Also, unless you can assume that all the strings are the same length, you might consider a different technique. When you use const int c = s.length(), you are telling the map<int,string> and vector<char> the length of EVERY string in your file are the exact same length. If the second string is shorter than the first, you will try to access characters in the string that don't exist! Note the
rep(j,0,c) (p->second).copy(&matrix[i][j],1,k++)
will fail since it thinks it has c characters, when it in fact will not.