C++ count chars, words, sentences in file using C-strings - c++

I am to use "C-strings, not C++ string objects" per teacher to read a paragraph from an input file and count characters, words, sentences, and the number of to-be verbs (to, be, am, are, is, was, were). My current program clears compiler but my character count and words count both off by two. My code to count sentences stops after counting one sentence. Any help as to my errors is appreciated. Still working to debug. My teacher basically told the class what strtok did and then literally told us to figure it out from there. Not asking for you to do it for me -- just tips/hints to get back in the right direction. Happy Easter.
#include <iostream>
#include <cstring>
#include <fstream>
#include <cstdlib>
using namespace std;
const int MAX_FILENAME = 256;
//Longest word length = 15 chars
const int MAX_WORD_CHARS = 16;
//Longest word in paragraph = 200 words
const int WORDS_MAX = 200;
//Max amount of chars in paragraph = 15*200
const int MAX_PARAGRAPH_CHARS = 3000;
//Max chars in a sentence
const int MAX_SENTENCE_CHARS = 200;
const int MAX_SENTENCES = 25;
const int NUM_TO_BE_VERBS = 5;
void readParagraph( ifstream& input, char [] );
int countWords( char [], char tp[][MAX_WORD_CHARS] );
int countSentences( char [] );
int main()
{
int i;
int words, sentences, average;
char filename[MAX_FILENAME];
ifstream input;
//Holds paragraph characters
char p[MAX_PARAGRAPH_CHARS];
const char TO_BE_VERBS[NUM_TO_BE_VERBS][MAX_WORD_CHARS] = { "am", "are", "is", "was", "were" };
const char BE[] = "be";
const char TO[] = "to";
char tp[WORDS_MAX][MAX_WORD_CHARS];
//Prompt user input file name
cout << "Enter input file name: ";
cin.get( filename, 256 );
//Open input file
input.open( filename );
//Check input file exists
if ( input.fail() )
{
cout << "Input file " << filename << " does not exist." << endl;
exit(1);
}
//Reads paragraph into array
readParagraph( input, p );
countWords( p, tp );
countSentences( p );
return(0);
}
void readParagraph( ifstream& input, char p[] )
{
int count = 0;
while ( input.get( p[count]) && (count < MAX_PARAGRAPH_CHARS) )
{
count++;
}
p[count - 1] = '\0';
cout << "Number of characters: " << count << endl;
}
int countWords( char p[], char tp[][MAX_WORD_CHARS] )
{
int i = 0;
char* cPtr;
cPtr = strtok( p, " " );
while ( cPtr != NULL )
{
strcpy( tp[i], cPtr );
i++;
cPtr = strtok( NULL, " " );
}
cout << "Number of Words: " << i << endl;
return(i);
}
int countSentences( char p[] )
{
int j = 0;
char* Ptr;
char sent[25];
Ptr = strtok( p, ".!?" );
while ( Ptr != NULL )
{
strcpy( sent, Ptr );
j++;
Ptr = strtok( NULL, ".!?" );
}
cout << "Number of sentences: " << j << endl;
return(j);
}

There are a number of problems with the code and a problem with the assignment. First, as has been mentioned, this is not the way that a professional programmer would approach this task, so shame on your instructor for not teaching students real-world use of C++. That said, there is still plenty to be learned with such an assignment. Here are some issues for you to consider and correct.
Unused variables
Unused variables are very often a sign of poor quality code. They clutter up the code, making it hard to understand and add nothing of value. Your compiler can help you find these kinds of problems if you ask it to be particularly picky. I used g++ to compile your code and used the following command line:
g++ -Wall -Wextra -pedantic --std=c++11 -o stringcount stringcount.cpp
It helpfully pointed out that i, words, sentences, average, TO_BE_VERBS, BE and TO are unused.
using namespace std;
Incorporating using namespace std; into every program you write is a bad habit that you should avoid. If your instructor is advising that you use this construct, be aware that you're going to have to unlearn this kind of bad habit if you ever decide to write code other than for that class.
Reading paragraphs
Your readParagraph routine includes this loop:
while ( input.get( p[count]) && (count < MAX_PARAGRAPH_CHARS) )
but consider that this will only stop if it reaches the end of the file or exceeds the MAX_PARAGRAPH_CHARS which is not the usual definition of a paragraph. Instead, you probably want to use some other indicator, such as a blank line, to indicate a paragraph has ended.
Separation of output from core logic
Many of your routines print as well as doing some kind of calculation. While this is a reasonable way to help troubleshoot non-working code, generally it's better to separate the calculation (as with readParagraph) from printing. That means that what would likely make more sense is to have readParagraph return an unsigned that represents the number of characters in the paragraph and not print anything. If something needs to be printed, print it from some other routine or from main.
Error handling
Look at your readParagraph function:
void readParagraph( std::ifstream& input, char p[] )
{
int count = 0;
while ( input.get( p[count]) && (count < MAX_PARAGRAPH_CHARS) )
{
count++;
}
p[count - 1] = '\0';
std::cout << "Number of characters: " << count << std::endl;
}
Is that \0 character really going in the right place? Where does it get written if there are no characters read?
Think carefully about the problem
Can you count the words in this sentence? I count eight. Your program might not because your countWords function includes this line:
cPtr = strtok( p, " " );
Note that words might end with a period or question mark and not necessarily with a space character. The strtok function can actually look for multiple delmiters within the same call, so you may wish to adjust that call.
Creating extra work
The countWords function carefully copies each discovered word into the tp array, but the tp array is then never used. If you don't use it, don't create it. It will make your program more durable and easier to troubleshoot as well as being slightly faster. The same is true of the mysterious sent variable in your countSentences function.
return is not a function
Don't write return(j); because return is not a function. Instead, just write return j; which is more idiomatic C and C++ style.
Magic numbers
You've used a number of const int declarations for constants in your program, which is a good thing. However, there are still some mysterious and unexplained "magic numbers" that are embedded in the program such as the 256 in this line:
std::cin.get( filename, 256 );
(Note that I've added std:: in front to show what it would look like when you omit the using namespace std; from your program.)

Here's how to debug code like this (which is related to, but not the same as, the way to write code well and avoid this predicament in the first place).
Step 1: pick an observed problem and lock it down.
The character count is off. Given the text "red apple", the code reports Number of characters: 10
Step 2: Find the relevant code and strip it down as far as you can, while still displaying the behavior.
void readParagraph( ifstream& input, char p[] )
{
int count = 0;
// while ( input.get( p[count]) && (count < MAX_PARAGRAPH_CHARS) )
char c;
while ( input.get(c))
{
count++;
}
// p[count - 1] = '\0';
cout << "Number of characters: " << count << endl;
}
Step 3: put in some diagnostic output statements so as to see what's going on (or, for more advanced students, run the whole thing in a debugger).
void readParagraph( ifstream& input, char p[] )
{
int count = 0;
char c;
while(input.get(c))
{
count++;
cout << count << ": " << c << endl;
}
cout << "Number of characters: " << count << endl;
}
The output is:
1: r
2: e
3: d
4:
5: a
6: p
7: p
8: l
9: e
10:
The code is counting spaces and carriage returns as characters.
Step 4: fix it.
How you deal with this depends on what you want it to count.
Go back to Step 1, repeat until you're satisfied.

Related

Output is not as expected

The idea of my program was to print individual digits of n.
But instead it prints all the digits at once in the first line and a bunch of zeroes or garbage values in subsequent lines.
I want to access each individual number as we can do with arrays.
Suppose the input is 1234, why doesn't it print 1\n2\n3\n4?
#include <iostream>
#include <cmath>
#include <stdlib.h>
using namespace std;
int main()
{
int* n=(int*)malloc(1000*sizeof(int));
cin>>*n;
int len;
len = log10(*n) + 1;
for(int i=0;i<len;i++)
{
cout<<n[i]<<endl;
}
}
n is declared as a pointer to a memory location which can store 1000 integer entities. When you use cin>>*n;, an integer value is read as input and store at the first memory block among the 1000 blocks. The individual digits of the integer are not stored in separate blocks, hence you can't print them separately.
For example, if the input is 123,
n[0] stores 123, n[1],n[2],...n[999] stores junk values.
To store a value in n[1], you will have to use cin again.
For some reason you think that
int* n=(int*)malloc(1000*sizeof(int));
cin>>*n;
will read a number and put each digit in a different element of the dynamic array n. If that happened then the rest of your code would work (kind of). But of course it doesn't. Instead the number read is put into *n (or, same thing, n[0]) and the rest of the dynamic array elements are uninitialised, which explains the garbage values you see.
I'm struggling to understand why you thought your code might behave in the way you wanted. I guess you are just an optimistic person and think that if you wish hard enough the compiler will understand. This seems to be quite a common attitude among beginners. Unfortunately programming isn't like that.
When you cin >> *n, you don't read the number digit by digit, but read in as a whole.
So when you cin >> *n and type in 1234, *n becomes 1234.
If you want to print all the individual digits, like 1\n2\n3\n4, you need to separate the digits for yourself:
int pos = 1;
while (*n != 0)
{
n[pos] = n % 10;
n /= 10;
++pos;
}
for (--pos; pos > 0; --pos)
{
cout << n[pos] << endl;
}
However, the easiest approach is to read in the number as a string, not a number, then print out the characters, that is the digits, one by one.
char str[1000];
cin >> str;
for (char *s = str; *s; ++s)
{
cout << *s << endl;
}
You can also convert the number into a string, and do the same:
#include <cstring>
using namespace std;
...
char str[1000];
sprintf(str, "%d", *n);
for (char *s = str; *s; ++s)
{
cout << *s << endl;
}
------- Original Answer:
If you want to print the first element of n:
cout << *n;
or
cout << n[0];
Your code
for(int i=0;i<len;i++)
{
cout<<n[i]<<endl;
}
means
cout << n[0] << endl;
cout << n[1] << endl;
cout << n[2] << endl;
...
cout << n[len-1] << endl;

Is there a better way to write this for C++? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 3 years ago.
Improve this question
The goal is to create substrings from an inputted string by extracting words which are separated by spaces.
The substrings have to be variables themselves.
Sounds easy, but what makes it hard is that you can only use strcpy, strcmp, strlen, strcat, strncpy, strncmp, strnlen, and strncat.
Example:
input:
"John 40 Hitman"
driver:
...
cout << word1 << endl
<< word2 << endl
<< word3 << endl;
output:
John
40
Hitman
Here is my code
#include <iostream>
#include <cstring>
#include <stdio.h>
int main(){
const char *string = "Name Age Job";
char name[10];
char age[10];
char job[10];
int length = strlen(string);
int temp = 0;
bool flag = false;
for(int i = 0; i < length + 1; i++){
if(isspace(string[i]) && !flag){
strncpy(name, string, i);
name[i] = '\0';
temp = i;
flag = !flag;
cout << name << endl;
continue;
}
if(isspace(string[i])){
strncpy(age, string + temp + 1, length - i - 1);
age[temp - i] = '\0';
temp = i;
cout << age << endl;
continue;
}
if(string[i] == '\0'){
strncpy(job, string + temp + 1, length);
job[temp - i] = '\0';
cout << job << endl;
}
}
It works but it has to use a flag boolean, strings are not dynamic, only works for a string with 2 spaces, and there is a lot of repeated code. Overall really janky, but I spent roughly two hours on this and I do not know how to improve it.
If you are wondering, this is indeed a homework problem, but it's an intro class and my professor only wants the correct output for a hard coded string with only 3 words. I, however, want to learn how to improve upon it and would be really grateful for any help. Thanks.
All you need to do is replace space ' ' with '\0'(the string end) thus creating 3 substrings from the original. The following program does that and just dumps the string to cout but you could hold the pointers in an array as well (eg. char* substring[3]).
int main(){
char string[] = "Name Age Job";
char* temp = string;
for(char* it = string; *it; ++it ) {
if (*it == ' ') {
*it = '\0';
std::cout << temp << std::endl;
temp= it + 1;
}
}
std::cout << temp << std::endl;
}
The proper way to do this with C functions only would be to use strtok, although that one chops up a string in-place.
Regarding your code, there's lot of needless branching and checks. You should avoid continue, it is an almost 100% certain sign of a loop in need of improvements. Whenever you find yourself needing it, there's usually a better way.
You should also avoid strncpy because as you've noticed, it is a pain to keep track of when it null terminates and when it doesn't. It's a dangerous function and much slower than memcpy, which could be used instead here.
Here is a simplified version based on using 2 pointers, one all the time set to point at the next space and one all the time set to point at the beginning of the next valid word.
#include <string.h>
#include <ctype.h>
#include <stdio.h>
const char* find_next_space (const char* str)
{
while(*str != '\0' && !isspace(*str))
str++;
return str;
}
int main (void)
{
const char str[] = "hello world how are you";
char substr[5][10];
const char* word_start = str;
for(size_t i = 0; i<5; i++)
{
if(*word_start == '\0')
break;
const char* next_space = find_next_space(word_start);
size_t length = (size_t)(next_space-word_start);
memcpy(substr[i], word_start, length);
substr[i][length] = '\0';
puts(substr[i]);
word_start = next_space+1;
}
}
This code simplifies things by not checking if a string would fit and it doesn't allocate memory. Real production-quality C code wouldn't use char [5][10] but rather a pointer array char* [5] where each pointer is set to point at dynamically allocated memory.
I agree with #acraig5075 as your code is more C than C++.
If you are thinking of writing this in C++ using the STL string, one way of doing this is the following.
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
std::vector<std::string> split_string( const std::string &srcString, const char &delimiterKeywrd )
{
/**
* Splits a string according to a keyword delimiter and returns a vector with the
* segments of the split string.
*
* Args:
* #param srcString: The required string to split.
* #param delimiterKeywrd: The delimiter keyword that the string will be splitted to
* #return segmentsVectr: A vector holding the segments of the srcString that was splitted.
*
*/
std::stringstream inputStr;
inputStr.str( srcString );
std::string segment;
std::vector<std::string> segmentsVectr;
while( std::getline( inputStr, segment, delimiterKeywrd ) )
{
segmentsVectr.push_back( segment );
}
return segmentsVectr;
}
int main() {
std::string inputStr{"John 40 Hitman"};
std::vector<std::string> result;
char delimiterKeywrd = ' ';
result = split_string( inputStr, delimiterKeywrd );
// Iterate through the vector and print items on a different line.
for ( const std::string &item : result )
{
std::cout << item << std::endl;
}
return 0;
}
Check std::string at cppreference and examples if you are not familiar.
Also here I am using std::stringstream which makes it easy to use std::getline.
If std::stringstream is not your preferred way you can always check this implementation from another question about splitting a string by character.
Hope this helps.

Why are my char functions not doing their job?

So I am still new to C++, and I'm trying to make a program that has the user input a string, and then my functions return the string in reverse case, all lower case, and then all uppercase. Instead I just keep receiving the first letter of the string back, always uppercase. Not sure what I am doing wrong. Any suggestions?
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
char answer[255] = "";
int max = strlen(answer);
void reverse() {
for (int i = 0; i < max; i++) {
if (islower(answer[i])) {
isupper(answer[i]);
}
else if (isupper(answer[i])) {
islower(answer[i]);
}
else if (isspace(answer[i])) {
isspace(answer[i]);
}
}
cout << answer[max];
}
void lower() {
for (int i = 0; i < max; i++) {
if (isupper(answer[i])) {
islower(answer[i]);
}
else {
answer[i] = answer[i];
}
}
cout << answer[max];
}
void upper() {
for (int i = 0; i < max; i++) {
if (islower(answer[i])) {
isupper(answer[i]);
}
else {
answer[i] = answer[i];
}
}
cout << answer[max];
}
int main() {
cout << "Please enter a word, or a series of words: " << endl;
cin >> answer[max];
reverse();
lower();
upper();
system("pause");
return 0;
}
islower(char) is just a built in function to check if the char is in lowercase or not. Same goes with isupper. It does not change the case of the character.
In order to convert to lowercase/uppercase, use tolower/toupper. This would return the character in the converted case. But, it is important that you need to assign the returned value to the character itself.
Refer to this answer for some more clarity related to islower, isupper, tolower and toupper.
And now coming to the point why it's printing just the 1st character: As #user4581301 has mentioned in his comment,
"cin >> answer[max]; will read exactly one character because answer[max] is exactly one character, the first character. In C++ you have to do things in order. For example, int max = strlen(answer); will provide an answer based on what is in that string at that time. Since the string was initialized one line earlier and contains an empty string, max will be 0."
Hence your cin should be cin >> answer. BUT, this will accept the 1st word of your sentence. In order to accept all the words including the spaces, use getline() instead. And for using this, answer should be declared as string answer instead of a char array.
This is how you accept a full sentence: getline(cin,answer);
And your variable max will give an error in a few compilers as being ambiguous. This is because of the using namespace std;. to avoid this, rename max to something else, like maxlen.
And finding the length of answer: It would be better if you call answer.length() after accepting the string from user rather than doing it globally.
Your working code should look something like this:
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
string answer;
int maxlen;
void reverse() {
for (int i = 0; i < maxlen; i++) {
if (islower(answer[i])) {
answer[i] = toupper(answer[i]);
}
else if (isupper(answer[i])) {
answer[i] = tolower(answer[i]);
}
else if (isspace(answer[i])) {
answer[i]=' ';
}
}
cout << "Reversed string: " + answer << endl;
}
void lower() {
for (int i = 0; i < maxlen; i++) {
if (isupper(answer[i])) {
answer[i] = tolower(answer[i]);
}
else {
answer[i] = answer[i];
}
}
cout << "Lower case string: " + answer << endl;
}
void upper() {
for (int i = 0; i < maxlen; i++) {
if (islower(answer[i])) {
answer[i] = toupper(answer[i]);
}
else {
answer[i] = answer[i];
}
}
cout << "Upper case string: " + answer << endl;
}
int main() {
cout << "Please enter a word, or a series of words: " << endl;
getline(cin,answer);
cout << "Original string: " + answer << endl;
maxlen = answer.length();
reverse();
lower();
upper();
return 0;
}
With the output:
Please enter a word, or a series of words:
ReVeRsAl UPPER aNd lower
Original string: ReVeRsAl UPPER aNd lower
Reversed string: rEvErSaL upper AnD LOWER
Lower case string: reversal upper and lower
Upper case string: REVERSAL UPPER AND LOWER
cin >> answer[max];
will read exactly one character because answer[max] is exactly one character, the character in the array at position max.
max is 0 because you have to do things in order. For example,
int max = strlen(answer);
will provide the length of answer at that time this line is reached. Since the string was initialized one line earlier
char answer[255] = "";
and contains an empty string, max will be 0. This means answer[max] is answer[0] Nothing in the code ever changes max, so it will remain 0.
OK, say we change things a little and rather than reading into a single character, we read into answer as a string. You will need to
cin.getline(answer, sizeof(answer));
because
cin >> answer;
will read one whitespace-delimited token. One word. Your stated goal is to read more than one word. istream::getline will read everything it finds into the first parameter up to the end of the line or it finds the number of characters specified in the second parameter minus 1 (in order to reserve space for the string's null terminator). sizeof(answer) is literally the size of the answer array in bytes. We're operating in byte-sized characters so the count of characters and number of bytes are the same. Extra care must be taken if multibyte characters are being used.
This seems like a good place to recommend using std::string and std::getline instead. They make a large number of problems, such as the maximum number of characters that can be read, vanish for the vast majority of cases.
I'm not going to use them here, though because the assignment likely has a "No strings" policy.
So now that we have cin.getline(answer, sizeof(answer)); reading the user's input we can work on getting the size for max. We could strlen, but we could also use istream::gcount to get the number of characters read by getline.
main now looks something like
int main() {
cout << "Please enter a word, or a series of words: " << endl;
cin.getline(answer, sizeof(answer));
max = cin.gcount();
reverse();
lower();
upper();
system("pause");
return 0;
}
Whole bunch of stuff can go wrong at this point.
using namespace std; can wreak havoc on the max because of possible collisions with std::max. In general, avoid using namespace std; The few letters it saves you from typing often are recovered by the time wasted debugging the weird errors it can introduce.
isupper(answer[i]); doesn't do anything useful as others have noted in the comments. You want
answer[i] = toupper(static_cast<unsigned char>(answer[i]));
See Do I need to cast to unsigned char before calling toupper(), tolower(), et al.? for why that insane-and-pointless-looking cast may be necessary. Thank you HolyBlackCat for bringing that to my attention.
Self assignments like
answer[i] = answer[i];
are pointless for reasons that should be obvious once you stop and think about it.
Likewise
else if (isspace(answer[i])) {
isspace(answer[i]);
}
May not be particularly useful. If answer[i] is a space, set it to a space? It's already a space. What it would do is replace other forms of whitespace, tabs and carriage returns, with a space. Newline has already been picked off by getline. Also probably needs a cast similar to the one used in the toupper example above. I'm still reading up on that.
As hinted at above,
cout << answer[max];
is not effective. It prints out one character, and if max has been fixed, answer[max] will be the terminating null. Instead print out the whole array.
cout << answer;
General suggestions:
Don't write much code at a time. Write a few lines, a function at the most, before compiling and testing. If you had tested
int main() {
cout << "Please enter a word, or a series of words: " << endl;
cin >> answer[max];
cout << answer;
}
You would have immediately seen data was not being read correctly. and fixed it before proceeding. By allowing errors to build up, you make it harder to find any one bug. You may correctly fix a bug only to find the fix undone or concealed by another bug.
Avoid using global variables. Try to place variables in the smallest possible scope. In this case, move answer and max into main and pass them to the other functions as parameters. This makes it a lot easier to keep track of who set what variable and when. It also helps prevent accidental Variable Shadowing.

Using pointers to find positions of characters between unbalances parentheses

I am given a C++ programming problem: In a string I need to find wether or not there are balanced parentheses. If not, using pointers I should find position of the characters between unclosed parentheses (between second opening and nearest closing).
The problem statement is a bit confusing, I know. I think it should work somehow like that:
Input #1:
((aba)aaab)
Output:
OK.
Input #2:
(aa(a)ab
Output:
Parentheses not balanced: between characters 1 and 6.
Code below solves part of problem with the closed parentheses check and also there is a structure to keep the address of the opening parenteses. I am not sure how exactly to use pointers for that purposes, some attempts did not give any result, so I need some help here.
#include<iostream>
#include<string>
#include<stack>
using namespace std;
struct br_data{
char br_t;
char *cptr; //store the address of the opening parenthesis
};
int main (){
string input;
int addr;
br_data br;
getline(cin, input);
stack<br_data> braces;
char *a = input[0];
auto init_char = static_cast<void*>(&a); //store the address of the first character in the input string
cout << static_cast<void*>(&a) << endl; //gives the address in memory
for(auto c: input) {
if (c == '(') {
br.br_t = c;
br.cptr = &c; //storing the address of the first parenhesis
braces.push(br);
} else if (c == ')' ) {
if (braces.empty())
cout << "This line does not contain unclosed parentheses\n";
if (!braces.empty())
braces.pop();
}
}
if (!braces.empty()){
//int addr = br.cptr;
cout << "This line does not contain unclosed parentheses\n";
//int pos = (&br.cptr) - (&a); //how to calculate the position??
cout << "Position of the second opening parenthis is " << () << endl;
//cout << "Position of the nearest closing parenthis is " << -how?? (static_cast<void*>(&br.cptr)) << endl;
}
if (braces.empty()){
cout << "Parentheses are balanced in this line\n";
}
return 0;
}
When you write
br.cptr = &c; //storing the address of the first parenhesis
you're actually storing the address of a local object of char type declared earlier:
auto c: input
By the moment you exit the loop it is officially dangling.
One simplest solution would be to actually consider string's characters, not their local copies:
for(auto &c: input) {
(and, even better, change auto into char for better clarity keeping source length the same). Then you can go on and see how your solution needs to be fixed further.
(A few extra free advice: input[0] is a rvalue reference of type char so it makes no sense to assign it to a variable of type char *, and what you try to do in that line is actually written as char *a = input.c_str(); or input.data() or even &input[0], pick the best option; and br.cptr is of type pointer-to-char already, so the character's position in a string would be calculated as br.cptr - a, you need to subtract the pointers themselves, not their addresses.)
#include <iostream>
using namespace std;
int main(){
char str[]="Hello Programming";
char *ptr;
char ch;
char s;
s='n';
ptr=str;
cout<<"To be found Character"<<endl;
cin>>ch;
while(*ptr++ != '\0')
if(*ptr==ch)
s='y';
if (s=='y')
cout<<"FOUND";
else
cout<<"not found";``
return 0;
}

I am trying to return a Character Array but, I'm only getting the first letter returned

I'm working on a small little thing here for school. After hours of researching, and a ton of errors and logic reworking I've almost completed my little program here.
I'm trying to take user input, store it into the string, get a character array from the string ( dont ask why, I just have to put this into a character array ), then get the reversed order of the phrase that the user entered. Here is my code:
#include "stdafx.h"
#include <iostream>
#include <String>
#include <cstring>
using namespace std;
using namespace System;
#pragma hdrstop
char* getCharArray(string);
string reversePhrase( int, char* );
void main(void)
{
string sPhrase = "";
int sSize = 0;
string sReversed = "";
char* cPhrase = NULL;
cout << "Welcome to the You Type It & We'll Reverse it! [Version 1.0] " << endl;
cout << "This program will reverse your phrase, and count how many characters are in it!" << endl;
cout << "To begin just enter a phrase." << endl;
cout << "Enter a phrase: ";
getline( cin, sPhrase);
sSize = sPhrase.length();
cout << endl;
cPhrase = getCharArray(sPhrase);
sReversed = reversePhrase( sSize, cPhrase );
cout << sReversed;
system("pause");
}
string reversePhrase(int size , char* cPhrase)
{
string sReversed = "";
int place = size;
for ( int i = 0; i < size ; i ++ )
{
sReversed.append(1, cPhrase[place]);
cout << "Current string: " << sReversed << endl;
cout << "Current character: " << cPhrase[place] << endl;
place--;
}
return sReversed;
}
char* getCharArray(string sPhrase)
{
int size = 1;
size = sPhrase.length();
char* cArray = NULL;
cArray = new char[size];
for (int i = 0 ; i < size ; i++)
{
cArray[size] = sPhrase.at(i);
}
return cArray;
}
When I type in "ownage" into the program, this is what I get returned:
It is almost like my Character Array is getting garbage collected before it can use all of the characters. This is probably an easy fix but, I just don't see how I can get around this one.
Try rewriting getCharArray like this
char* getCharArray(string sPhrase)
{
int size = 1;
size = sPhrase.length();
char* cArray = NULL;
cArray = new char[size+1]; // NOTE
for (int i = 0 ; i < size ; i++)
{
cArray[i] = sPhrase.at(i); // NOTE
}
}
cArray[size]=0; // NOTE
return cArray;
}
Note that the assignment in the loop now uses the index variable. Also, you need to allocate one extra char in the array to set the null terminator for the string and then you need to set it at the end.
You'll also need to think about deallocating the array at some point
The bug is in this line:
cArray[size] = sPhrase.at(i);
That size should be your loop index.
You should probably look at using std::string more, and not poke around with character arrays when there's no need to.
Why use a char array at all? It's not only useless – it complicates the code substantially (the usage of your function is more difficult, and you've forgotten to free the memory allocated by new!). Why not just have the following function:
string reverse(string const& input);
(Passing the argument by const reference instead of by value saves you a copy!)
In fact, implementing the function only takes a single line using the features of the string class (one of its constructors takes two iterators):
string reverse(string const& input) {
return string(input.rbegin(), input.rend());
}
reversePhrase is also not correct. Try something like this:
string reversePhrase(int size , char* cPhrase)
{
string sReversed = "";
sReversed.resize(size);
int place = size - 1;
for ( int i = 0; i < size ; i ++ )
{
sReversed [i] = cPhrase[place];
cout << "Current string: " << sReversed << endl;
cout << "Current character: " << cPhrase[place] << endl;
place--;
}
return sReversed;
}
First, start the array with -1. After that, use a for loop with -1 and increment inside the loop. Then, you can get the first element of the array.