Read a char array and modify it - c++

So for this program the user gives a text and it must print the text back modifying in these ways by adding and removing space between words:
Each line should contain 60 characters and be aligned left and right
In each line the biggest space between two words must be bigger than the smallest by only one character and a bigger space must be righter than a smaller one. This is what I have managed to do yet, but without any success.
I tried C++ strings instead of a char array but my knowledge about them is limited yet.
#include <iostream>
using namespace std;
bool isletter(char c) {
return c >= 'a' and c <= 'z' or c >= 'A' and c <= 'Z';
}
int main() {
int c, i = 0, constant = 0, counter = 0;
char text[1500], original[1500];
do {
c = getchar();
original[i] = c;
i++;
} while (c != EOF);
for (int j = 0; j <= i; j++) {
if (original[j] == ' ') {
int n = 0;
j = constant;
while (not isletter(original[j])) {
n++;
text[constant] = original[j];
j = j + n;
}
counter++;
} else if (text[j] == '\n') {
text[j] = ' ';
counter++;
} else {
text[j] = original[j];
counter++;
}
}
for (int i = 0; i < counter; i++) {
cout << text[i];
}
}

Related

Visual C++ assert- String subscript out of range

My program is a solution for the Day 6 question in Advent of Code 2015. I get an error when I use "Start Without Debugging" and enter the puzzle input in the output window.The image contains the exact error I received. The error is related to "string subscript out of range". I would like help in resolving this error.
const int r = 1000;//global variable
const int c = 1000;//global variable
int lights[r][c];//global array
void instruction(string inp)//extracting OFF, ON, or toggle indication from the instruction
{
int* loc;
int coord[4] = { 0 };
char cond = inp[7];
loc = &coord[3];
switch (cond)
{
case 'f':
coordinates(loc, inp);
execute(coord, cond);
break;
case 'n':
coordinates(loc, inp);
execute(coord, cond);
break;
default:
coordinates(loc, inp);
execute(coord, cond);
break;
}
}
void coordinates(int* loc, string inp)//extracting coordinates from the instruction
{
int i, k = 0, l;
l = inp.length()-1;
for (i = l; inp[i] != ','; i--)
{
*loc += (inp[i]-'0') * pow(10,k);
k++;
}
i--;
loc--;
k = 0;
for (; inp[i] != ' '; i--)
{
*loc += (inp[i]-'0') * pow(10,k);
k++;
}
i = i - 9;
loc--;
k = 0;
for (; inp[i] != ','; i--)
{
*loc += (inp[i]-'0') * pow(10,k);
k++;
}
i--;
loc--;
k = 0;
for (; inp[i] != ' '; i--)
{
*loc += (inp[i]-'0') * pow(10,k);
k++;
}
}
void execute(int coord[], char cond)
{
int i, j;
for (i = coord[0]; i <= coord[2]; i++)
{
for (j = coord[1]; j <= coord[3]; j++)
{
if (cond == 'f')
lights[i][j] &= 0;
else if (cond == 'n')
lights[i][j] |= 1;
else
lights[i][j] = ~lights[i][j];
}
}
}
int main()
{
int i, j, k, count = 0;
string inp;
for (i = 0;;i++)
{
cout << "Enter an instruction" << endl;
cin >> inp;
if (inp != "xx")//To manually move to counting the number of lights turned ON
instruction(inp);
else
{
for (j = 0; j < r; j++)
{
for (k = 0; k < c; k++)
{
if (lights[j][k])
count++;
}
}
cout << endl << "Number of lights lit " << count;
break;
}
}
return 0;
}
The problem is most likely this loop (from the coordinates function):
l = inp.length()-1;
for (i = l; inp[i] != ','; i--)
{
*loc += int(inp[i]) * (10 ^ k);
k++;
}
In the very first iteration of the loop then i will be equal to l which is the length of the string, which is out of bounds.
You also don't check if you go out of bounds in the second direction (i becomes negative). You have this problem in all your loops in the coordinates function.
On another note, casting a character to int will not convert a digit character to its corresponding integer value.
Assuming ASCII encoding (the most common encoding available) then the character '2' (for example) will have the integer value 50.
Also the ^ operator it bitwise exclusive OR, not any kind of "power" or "raises" operator. It seems you could need to spend some more times with some of the basics of C++.

Reverse an array without affecting special characters

Is it possible to reverse an array without affecting the special characters ? By special characters, I mean anything characters not included from 'a' to 'z' and 'A' to 'Z'. I am short of ideas to build the algorithm, I still haven't it figured out.
One simple solution would be to Simple Solution:
1) Create a temporary character array --> ex: myArr[].
2) Copy alphabetic characters from the given array to myArr[].
3) Reverse myArr[] using standard string reversal algorithm.
4) Now traverse input string and myArr in a single loop. Wherever there is alphabetic character is input string, replace it with current character of myArr[].
Little problem with above solution, it requires extra space and it does two traversals of input string.
You can reverse with one traversal and without extra space. Below is algorithm.
1) Let input string be 'str[]' and length of string be 'a'
2) l = 0, r = a-1
3) While l is smaller than r, do following
a) If str[l] is not an alphabetic character, do l++
b) Else If str[r] is not an alphabetic character, do r--
c) Else swap str[l] and str[r]
Here's a solution that will do it "in place" in one pass.
bool isspecial(char c)
{
if ((c >= 'a') && (c <= 'z')) return false;
if ((c >= 'A') && (c <= 'Z')) return false;
return true;
}
void rev(char* array, int N)
{
int i = 0; // i points to the first index of the array
int j = N - 1; // j points to the last index of the array
while (i < j)
{
if (isspecial(array[i]))
{
i++;
}
else if (isspecial(array[j]))
{
j--;
}
else
{
char tmp = array[i];
array[i] = array[j];
array[j] = tmp;
i++;
j--;
}
}
}
Console.WriteLine("enter any string");
string str = Console.ReadLine();
string[] revstr = new string[str.Length];
for (int i = 0; i < str.Length; i++)
{
int ch = Convert.ToInt16(str.ToLower()[i]);
if ((ch < 97 || ch > 122))
{
revstr[i] = str[i].ToString();
}
}
for (int k = str.Length - 1; k >= 0; k--)
{
int ch = Convert.ToInt16(str.ToLower()[k]);
if (!(ch < 97 || ch > 122))
{
for (int j = 0; j < str.Length; j++)
{
if (revstr[j] == null)
{
revstr[j] = str[k].ToString();
break;
}
}
}
}
for (int s = 0; s < revstr.Length; s++)
{
Console.Write(revstr[s]);
}
If you want the position of the special characters to remain the same and the rest of the string to be reversed then this should work -
#include <iostream>
using namespace std;
void swap(char& a, char& b)
{
char temp = a;
a = b;
b = temp;
}
int main()
{
string s = "Hell$o World";
for(int i = 0, j = s.length() -1;i < s.length()/2; i++, j--) {
while((s[i] <= 'a' && s[i] >= 'Z') || s[i] >= 'z' || s[i] <= 'A') {
i++;
}
while((s[j] <= 'a' && s[j] >= 'Z') || s[j] >= 'z' || s[j] <= 'A') {
j--;
}
swap(s[i], s[j]);
}
cout << s << endl; //dlro$W olleH
return 0;
}

Printing an integer value from an ASCII character

I am trying to implement the function stoi() in c++. I have made an int array arr to store the integer ASCII of all elements of char_arr. This works fine if I print the values from my char_arr array because its a character array. But, how do I transfer my integer values from the char array to an int array and print only the numbers and not their ASCII?
Code:
int stoi(){
int *arr = new int [strlen(char_arr)];
for (int i=0; char_arr[i]!='\0'; ++i){
arr[i] = char_arr[i];
}
for (int i=0; char_arr[i] != '\0'; ++i){
if (arr[i] >= 48 && arr[i] <= 57){
cout << char_arr[i];
}
}
}
First of all, remove the first loop and use char_arr directly. You don't need to hold ints to make it work.
As for printing int values, you can use this:
for (int i = 0; char_arr[i] != '\0'; ++i) {
if (char_arr[i] >= '0' && char_arr[i] <= '9') { //I would suggest you to use this syntax instead of raw ASCII codes.
cout << (char_arr[i] - '0');
}
}
int stoi(){
/* if you do not use arr.
int *arr = new int[strlen(char_arr)];
for (int i = 0; char_arr[i] != '\0'; ++i){
arr[i] = char_arr[i];
}
*/
int sign = 1, value = 0;
if (*char_arr == '+') {
++char_arr;
}
else if (*char_arr == '-') {
++char_arr;
sign = -1;
}
while (*char_arr) {
if (*char_arr >= '0' && *char_arr <= '9') {
value = value * 10 + *char_arr - '0';
++char_arr;
} else {
break;
}
}
return sign * value;
}
Here's the one I came up with:
#include <cstdio>
#include <cstring>
#define _BASE_ 10
int main(int argc, char **argv)
{
char ascii[] = "474927";
signed int value = 0;
signed int ascii_len = strlen(ascii);
int pos = 0;
for(signed int i = ascii_len-1; i >= 0; i--)
{
if(i == 0 && ascii[i] == '-')
{
value *= -1;
continue;
}
int base = 1;
if(pos > 0)
{
base = _BASE_;
for(int j = 1; j < pos; j++)
base *= _BASE_;
}
value += base * (ascii[i] - 48);
pos++;
}
printf("Value: %d\n", value);
return 0;
}

How can I reverse the words in a sentence without using built-in functions?

This was the interview question:
How to convert Dogs like cats to cats like Dogs ?
My code shows: cats like cats. Where am I making the mistakes?
#include <iostream>
using namespace std;
int main()
{
char sentence[] = ("dogs like cats");
cout << sentence << endl;
int len = 0;
for (int i = 0; sentence[i] != '\0'; i++)
{
len++;
}
cout << len << endl;
char reverse[len];
int k = 0;
for (int j = len - 1; j >= 0; j--)
{
reverse[k] = sentence[j];
k++;
}
cout << reverse << endl;
int words = 0;
char str[len];
for (int l = 0; reverse[l] != '\0'; l++)
{
if (reverse[l] == ' ' || reverse[l] == '\0') // not sure about this part
{
for (int m = l; m >= 0; m--)
{
str[words] = reverse[m];
words++;
}
}
}
cout << str;
return 0;
}
I know you can do this using pointers, stack, vectors... but interviewer was not interested in that!
This is a fixed version of your sample code:
Your principal problem is that every time you found and ' ' or '\0' you copy the bytes of the reverse string from the beginning to that point. Example in loop 5 you copy from index 0-5 (stac) from reverse to str in reverse order, but in in loop 10 you copy from index 0-10 (stac ekil) from reverse to str in reverse order, until here you have already the printed result string ('cats like cats'), and the same in loop 15 all of this incrementing the index of str, in the last loop you are written pass the end of the valid memory of str (and because of that not printed as output).
You need to keep track when end the last word reversed to reverse only the actual word, and not the string from the beginning to the actual index.
You don't want to count the special character (' ' and '\0') in the reversing of the words, you would end with cats like\0dogs
Modified sample code provided:
#include <iostream>
using namespace std;
int main() {
char sentence[] = ("dogs like cats");
cout << sentence << endl;
int len = 0;
for (int i = 0; sentence[i] != '\0'; i++) {
len++;
}
cout << len << endl;
char reverse[len];
int k = 0;
for (int j = len - 1; j >= 0; j--) {
reverse[k] = sentence[j];
k++;
}
cout << reverse << endl;
int words = 0;
char str[len];
// change here added last_l to track the end of the last word reversed, moved
// the check of the end condition to the end of loop body for handling the \0
// case
for (int l = 0, last_l = 0; ; l++) {
if (reverse[l] == ' ' || reverse[l] == '\0')
{
for (int m = l - 1; m >= last_l; m--) { // change here, using last_t to
str[words] = reverse[m]; // only reverse the last word
words++; // without the split character
}
last_l = l + 1; // update the end of the last
// word reversed
str[words] = reverse[l]; // copy the split character
words++;
}
if (reverse[l] == '\0') // break the loop
break;
}
cout << str << endl;
return 0;
}
Some code, written with the restriction of using the most simple features of the language.
#include <iostream>
// reverse any block of text.
void reverse(char* left, char* right) {
while (left < right) {
char tmp = *left;
*left = *right;
*right = tmp;
left++;
right--;
}
}
int main() {
char sentence[] = "dogs like cats";
std::cout << sentence << std::endl;
// The same length calculation as sample code.
int len = 0;
for (int i = 0; sentence[i] != '\0'; i++) {
len++;
}
std::cout << len << std::endl;
// reverse all the text (ex: 'stac ekil sgod')
reverse(sentence, sentence + len - 1);
// reverse word by word.
char* end = sentence;
char* begin = sentence;
while (end < sentence + len) {
if (*end != ' ')
end++;
if (end == sentence + len || *end == ' ') {
reverse(begin, end - 1);
begin = end + 1;
end = begin;
}
}
std::cout << sentence << std::endl;
return 0;
}
Dissecting your algorithm in pieces. First, you find the length of the string, not including the null char terminator. This is correct, though could be simplified.
size_t len = 0;
for (int i = 0; sentence[i] != '\0'; i++) {
len++;
}
cout << len << endl;
This could easily be written simply as:
size_t len = 0;
while (sentence[len])
++len;
Next, you reverse the entire string, but the first defect surfaces. The VLA (variable length array) you declare here, (which you don't need and shouldn't use, as it is a C++ extension and non-standard) does not account for, nor set, a terminating null-char.
char reverse[len]; // !! should be len+1
int k = 0;
for (int j = len - 1; j >= 0; j--) {
reverse[k] = sentence[j];
k++;
}
// !! Should have reverse[k] = 0; here.
cout << reverse << endl; // !! Undefined-behavior. no terminator.
This temporary buffer string is not needed at all. There is no reason you can't do this entire operation in-place. Once we calculate len correctly, you simply do something like the following to reverse the entire sequence, which retains the null char terminator in proper position:
// reverse entire sequence
int i = 0, j = len;
while (i < j--)
{
char c = sentence[i];
sentence[i++] = sentence[j];
sentence[j] = c;
}
Next we move to where you try to reverse each internal word. Again, just as before, the buffer length is not correct. It should be len+1. Worse (hard to imagine), you never remember where you left off when finding the end point of a word. That location should be the next point you start checking for, and skipping, whitespace. Without retaining that you copy from current point all the way back to the beginning of the string. which essentially blasts cats over dogs.
int words = 0;
char str[len]; // !! should be len+1
for (int l = 0; reverse[l] != '\0'; l++)
{
if (reverse[l] == ' ' || reverse[l] == '\0') // not sure about this part
{
for (int m = l; m >= 0; m--) {
str[words] = reverse[m];
words++;
}
}
}
cout << str; //!! Undefined behavior. non-terminated string.
Once again, this can be done in-place without difficulty at all. One such algorithm looks like this (and notice the loop that reverses the actual word is not-coincidentally the same algorithm as reversing our entire buffer):
// walk again, reversing each word.
i = 0;
while (sentence[i])
{
// skip ws; root 'i' at beginning of word
while (sentence[i] == ' ') // or use std::isspace(sentence[i])
++i;
// skip until ws or eos; root 'j' at one-past end of word
j = i;
while (sentence[j] && sentence[j] != ' ') // or use !std::isspace(sentence[j])
++j;
// remember the last position
size_t last = j;
// same reversal algorithm we had before
while (i < j--)
{
char c = sentence[i];
sentence[i++] = sentence[j];
sentence[j] = c;
}
// start at the termination point where we last stopped
i = last;
}
Putting It All Together
Though considerably simpler to use pointers than all these index variables, the following will do what you're attempting, in place.
#include <iostream>
int main()
{
char s[] = "dogs like cats";
std::cout << s << '\n';
size_t len = 0, i, j;
while (s[len])
++len;
// reverse entire sequence
i = 0, j = len;
while (i < j--)
{
char c = s[i]; // or use std::swap
s[i++] = s[j];
s[j] = c;
}
// walk again, reversing each word.
i = 0;
while (s[i])
{
// skip ws; root 'i' at beginning of word
while (s[i] == ' ') // or use std::isspace
++i;
// skip until ws or eos; root 'j' at one-past end of word
j = i;
while (s[j] && s[j] != ' ') // or use !std::isspace
++j;
// remember the last position
size_t last = j;
while (i < j--)
{
char c = s[i]; // or use std::swap
s[i++] = s[j];
s[j] = c;
}
// start at last-left posiion
i = last;
}
std::cout << s << '\n';
return 0;
}
Output
dogs like cats
cats like dogs
My advise would be to break up the original string into an array of words, reverse that array. Then add those words to your reversed sentence with a space in between.
Since they asked for no libraries, I assumed no std::string, no vectors, nothing at all and so I wrote it in C.. the only thing used is printf. Everything else is from scratch :l
The idea is that you reverse the array first. Then split the array by space and reverse each word.
Example: http://ideone.com/io6Bh9
Code:
#include <stdio.h>
int strlen(const char* s)
{
int l = 0;
while (*s++) ++l;
return l;
}
void reverse(char* str)
{
int i = 0, j = strlen(str) - 1;
for(; i < j; ++i, --j)
{
str[i] ^= str[j];
str[j] ^= str[i];
str[i] ^= str[j];
}
}
void nulltok(char* str, char tok, int* parts)
{
int i = 0, len = strlen(str);
*parts = 1;
for (; i < len; ++i)
{
if (str[i] == tok)
{
str[i] = '\0';
++(*parts);
}
}
}
char* reverse_sentence(char* str)
{
char* tmp = str;
reverse(str);
int i = 0, parts = 0, len = strlen(str);
nulltok(str, 0x20, &parts);
while(parts--)
{
reverse(str);
str += strlen(str) + 1;
}
for(; i < len; ++i)
if (tmp[i] == '\0')
tmp[i] = 0x20;
return tmp;
}
int main(void)
{
char str[] = "dogs like cats";
printf("%s", reverse_sentence(str));
return 0;
}
My solution
#include<iostream>
#include<string.h>
using namespace std;
int main()
{
string str;
cout<<"enter the sentence"<<endl;
getline(cin,str);
char* pch;
pch = strtok((char*)str.c_str()," ");
string rev = "";
while(NULL != pch)
{
rev.insert(0,pch);
rev.insert(0," ");
pch = strtok(NULL," ");
}
cout<<"the reversed string is :"<<rev<<endl;
return 0;
}

Reversing words of a sentence?

I do not understand what I am doing wrong. It looks like this should work:
Calling reverse_reverse("this house is blue");
should first print out "this house is blue", then "blue is house this"..
void reverse_reverse(char * str) {
char temp;
size_t len = strlen(str) - 1;
size_t i;
size_t k = len;
for(i = 0; i < len; i++) {
temp = str[k];
str[k] = str[i];
str[i] = temp;
k--;
if(k == (len / 2)) {
break;
}
}
cout << str << endl;
i = 0;
for(k = 0; k < len; k++) {
if(str[k] == ' ') {
size_t a = k;
for(size_t b = i; b < k; b++) {
temp = str[b];
str[b] = str[a];
str[a] = temp;
a--;
if(a == (((k - i) / 2) + i)) {
break;
}
}
}
i = k + 1;
}
cout << str << endl;
}
You have
i = k+1
and then the for loop
for(size_t b = i; b < k; b++)
This will never go in as i > k before the start of the loop and thus b > k.
Perhaps you meant to have that line in the if block:
if (str[k] == ' ') {
...
i = k+1; // <----- Here
}
// i = k+1; // Instead of here.
I don't think that will work either, but will get you much closer to what you desire.
It would be easier to read and understand and debug your code if it were simpler. Note that you repeat code to reverse a sequence of characters in two different places -- you should use a subroutine. A simpler, more intuitive, and faster algorithm than the one you're using is
/* reverse s[first ... last] in place */
void reverse(char* s, int first, int last){
for( ; first < last; first++, last-- ){
char c = s[first];
s[first] = s[last];
s[last] = c;
}
}
Then your program reduces to something simple:
void reverse_reverse(char* s) {
int len = strlen(s);
reverse(s, 0, len - 1);
for( int word = 0, i = 0;; i++ ){
if( i == len || s[i] == ' ' ){
reverse(s, word, i-1);
if( i == len ) break;
word = i + 1;
}
}
}
Note that I moved the end test inside of the for loop to handle the last word in the string if it isn't followed by a space.
Instead of reversing the whole string once and then each word another time, you could do something like this:
void reverse(const char *s)
{
int e = strlen(s) - 1;
int b = e;
while (b) {
while (b && s[b - 1] != ' ')
b--;
int i;
for (i = b; i <= e; ++i)
putchar(s[i]);
while (b && s[b - 1] == ' ') {
printf(" ");
b--;
}
e = b - 1;
}
}