How can I read input while it exists? - c++

#define _CRT_SECURE_NO_WARNINGS
#include <cmath>
#include <cstdio>
#include <string>
int main(){
char s = ' ';
while (s != NULL)
{
scanf ("%c", &s);
int a = 0;
if (s == '"')
{
if (a == 0) printf("``");
else printf("''");
a = 1- a;
}
else
printf("%c", s);
}
return 0;
}
this is my code, I'm new in C++, I'm writing this for uva.onlinejudge.org. the input is some text that we don't know it's size. I wanted to know how to get input while it exists ( I tried s != NULL but the program doesn't stop and gets the last char for ever)

#include <iostream>
// ...
while ( std::cin.get(s) )
{
// your code goes here
}
BTW in your existing code, scanf should be std::scanf, etc. The standard functions are all in the std:: namespace, and may or may not also be found in the global namespace.

Related

Questions regarding C++ string

phrase.erase(remove_if (phrase.begin(), phrase.end(), ::isdigit), phrase.end());
In the above code, why do I have to use :: even though I used using namespace std?
#include "Palindrome.h"
#include <iostream>
#include <string.h>
#include <algorithm>
using namespace std;
Palindrome::Palindrome (string Phrase){
phrase=Phrase;
}
void Palindrome::removeNonLetters()
{
phrase.erase(remove_if (phrase.begin(), phrase.end(), ::isdigit), phrase.end());
phrase.erase(remove_if (phrase.begin(), phrase.end(), ::ispunct), phrase.end());
phrase.erase(remove_if (phrase.begin(), phrase.end(), ::isspace), phrase.end());
}
void Palindrome::lowerCase()
{
for (int i=0; i<phrase.length(); i++)
{
phrase[i] = tolower(phrase[i]);
}
}
bool Palindrome::isPalindrome()
{
int length=phrase.length();
int a=0;
for (int i=0;i<length/2;i++)
{
if(phrase[i] != phrase[length-a-1])
{
return false;
break;
}
a++;
}
return true;
}
The above code is to check if the string is a Palindrome. I don't understand why I need to use the first part which is
Palindrome::Palindrome (string Phrase){
phrase=Phrase;
}
I will always get "yes" if I deleted the above part.
The test code in main is
if(test.Palindrome::isPalindrome() == 1){
cout<<"Yes"<<endl;
}
else {
cout<<"No"<<endl;
}
One more question. I try to change the lowercase of above code, I got error. Do anyone know what happen with it? The new code was from https://www.geeksforgeeks.org/conversion-whole-string-uppercase-lowercase-using-stl-c/
Before
void Palindrome::lowerCase()
{
for (int i=0; i<phrase.length(); i++)
{
phrase[i] = tolower(phrase[i]);
}
}
After
void Palindrome::lowerCase(){
transform(phrase.begin(), phrase.end(), phrase.begin, ::tolower);
}
Can anyone explain it to me? Many thanks!
There are multiple isdigit, ispunct, and isspace functions - ones in the global namespace in the <ctype.h> header, and several in the std namespace in the <cctype> and <clocale> headers. Prefixing them with :: says you want to use the ones from the global namespace.
You need to use <string> instead of <string.h> in order to use the std::string class.
Assuming test is a Palindrome object, then test.Palindrome::isPalindrome() should be just test.isPalindrome().
If you omit the Palindrome constructor, then the phrase member remains blank, and your isPalindrome() implementation returns true for a blank phrase (length is 0) because there is nothing for the for loop to check. Which is technically correct - a blank string is a palindrome.
The :: indicates that you're using isdigit and the others from the global namespace. The isdigit is a part of other header files, such as <ctype.h>.

How to count characters that appear twice consecutively

I'm using C++. So far, my code goes like this:
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <windows.h>
int main() {
char word[100]; int ctr, count = 0;
printf("Enter string: "); gets(word);
ctr = 1;
while (word[ctr] != '\0') {
if (word[ctr-1] == word[ctr]) count++;
ctr++;
}
printf("%d", count);
return 0;
}
Sample Run
Enter string: mississippi
3
Enter string: mmmmrrnzzz
6
I've got the first sample run correctly (mississippi) with only 3 characters appearing twice consecutively but not on the second sample run (mmmmrrnzzz) with output 6.
My problem is that, it should not be 6 but 4 instead. 1 for the first two consecutive m, another separate 1 for the next two consecutive m, 1 for r, and 1 for z. I want a separate count for the first "mm" and the second "mm" and also for the "zz" but I don't know how.
I'm a freshman and very new to programming. I wish I could explain better. I'm hoping you could help me. Thank you.
In case of multiple couples like mmmm you need to make a double incrementation of your counter:
#include <stdio.h>
#include <string.h>
int main()
{
char word[100];
int ctr;
int count = 0;
printf("Enter string: ");
gets(word);
int len = strlen(word);
ctr = 1;
while (ctr<len) {
if (word[ctr-1] == word[ctr])
{
count++;
ctr++;
}
ctr++;
}
printf("%d", count);
return 0;
}
First of all the program looks like a C program. In fact you are not using C++. You are using C.:) At least for example in C++ you should use header
#include <cstdio>
instead of
#include <stdio.h>
and so on.
And moreover it has a bug because in general the string can be empty. In this case the condition of the loop skips the first zero-terminating character and the program has undefined behaviour.
Here is a correct approach
#include <stdio.h>
int main( void )
{
const char *s = "mmmmrrnzzz";
size_t count = 0;
while ( *s++ )
{
if ( *s == *( s - 1) )
{
++count;
++s;
}
}
printf( "count = %zu\n", count );
}
The output is
count = 4
Take into account that function gets is unsafe and is not supported by the C (or C++) Standard any more.
You should use function fgets instead of gets.
This will work
#include <stdio.h>
#include <string.h>
int main() {
char word[100]; int ctr, count = 0;
printf("Enter string: "); gets(word);
int len=strlen(word);
ctr = 1;
while (ctr<len) {
if (word[ctr-1] == word[ctr])
{
count++;
ctr++;
}
ctr++;
}
printf("%d", count);
return 0;
}
A standard library version:
#include <algorithm>
#include <iostream>
#include <string>
int main()
{
int count{};
std::string s;
std::cin >> s;
for (auto it = s.begin(); (it = std::adjacent_find(it, s.end())) != s.end(); it += 2)
++count;
std::cout << count << '\n';
}

I am getting a segmentation fault in this code and can't understand why?

I am trying to code a program where it takes a program as an input and prints out all the comments written in that program in a separate line.
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
string str;
while(getline(cin,str)) {
int i;
// cout<<str;
for(i=0;str[i]!='/' && str[i+1] !='/';i++);
//cout<<i;
for(i;str[i]!='\n';i++) {
// cout<<i;
cout<<str[i];
}
cout<<endl;
}
return 0;
}
I am getting a segmentation fault in this code and I can't understand why. This is part of a code of a problem in hackerrank https://www.hackerrank.com/challenges/ide-identifying-comments/copy-from/12957153
As commented in your question your code is wrong. First you are treating std::string object, returned by getline, as character array. Secondly your for loops never end if there is no // or \n found in input string. So obviously it will crash. Below is the modified code.
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
string str;
while(getline(cin,str)) {
int i;
// cout<<str;
size_t len = str.length();
const char *cstr = str.c_str();
for(i=0; (cstr[i]!='/' && cstr[i+1] !='/' && i < len); i++)
//cout<<i;
for(; cstr[i]!='\n' && i < len;i++) {
// cout<<i;
cout<<cstr[i];
}
cout<<endl;
}
return 0;
}
int main() {
while(getline(cin,str)) {
int i, len = str.size();
//always make sure that you are not accessing
//contents after your string has ended
for(i=0; i < (len - 1) && !(str[i] == '/' && str[i+1] == '/'); i++);
//note that i here might be the last alphabet
//if there's no comment
if(i < len && str[i] != '/')
i++;
//checking if str[i] != '\n' is not a good idea
//as c++ stl strings are not temrinated by '\n'
if(i < len) {
for(; i < len; i++)
cout << str[i];
cout << endl;
}
}
return 0;
}
Also note that both of the following codes won't terminate at the 4th character, c++ stl strings are not terminated by these characters.
string str = "hahahaha";
str[4] = '\n';
cout << str;
str[4] = '\0';
cout << str;
This is much easier to write and probably much faster than the other solutions to date.
#include <iostream>
int main()
{
std::string str;
while (std::getline(std::cin, str))
{
size_t loc = str.find("//");
if (loc != str.npos)
{
std::cout << str.substr(loc + 2)<< std::endl;
}
}
return 0;
}
It is also wrong.
Here is a nice, clean, and simple state machine version. Also pretty close to worst-case for speed. Thing is it's closest to being right, even though it is also wrong.
#include <iostream>
enum states
{
seeking1,
seeking2,
comment
};
int main()
{
std::string str;
while (std::getline(std::cin, str))
{
states state = seeking1;
for (char ch:str)
{
switch (state)
{
case seeking1:
if (ch == '/')
{
state = seeking2;
}
break;
case seeking2:
if (ch == '/')
{
state = comment;
}
else
{
state = seeking1;
}
break;
case comment:
std::cout << ch;
break;
}
}
if (state == comment)
{
std::cout << std::endl;
}
}
return 0;
}
Why are these approaches all wrong? Consider the line
cout << "Hi there! I am \\Not A Comment!" << endl;`
You can't just look at the \\, you also need the context. This is why the state machine above is the better option. It can be modified to handle, at the very least, states for handling strings and block comments.

How to read string from stdin until meet blank lines

Consider a simple program. It must take string from stdin and save to variable.
It is not stated how many lines of input will be taken, but program must terminate if meet newline.
For example:
stdin:
abc
abs
aksn
sjja
\n
I tried but it doesn't work. Here is my code:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
// Constant
#define max 100000
struct chuoi
{
char word[10];
};
chuoi a[max];
void readStr()
{
int i=0;
while ( fgets(a[i].word, 10,stdin) != NULL)
{
if (a[i].word[0] == ' ') break;
a[i].word[strlen(a[i].word)-1] = '\0'; //replaced \n by \0
i++;
}
//length = i;
}
int main()
{
readStr();
return 0;
}
So, how to solve this problem?
One alternative here is to use std::getline to get each line. If the line is empty, or the input fails, then exit the loop.
void readStr()
{
std::string str;
while ( std::getline(std::cin, str) && str.length() )
{
// use the string...
}
}
Adding the std::getline and use of std::vector to your sample code, and keeping with the spirit of your original sample;
#include <string>
#include <iostream>
#include <vector>
const std::size_t Max = 100000;
struct chuoi
{
explicit chuoi(std::string const& str) : word(str)
{
}
std::string word;
};
void readStr(std::vector<chuoi>& a)
{
std::string str;
while ( std::getline(std::cin, str) && str.length() )
{
a.push_back(chuoi(str));
}
}
void writeStr(std::vector<chuoi> const& a)
{
for (auto i = a.begin(); i != a.end(); ++i) {
std::cout << i->word << std::endl;
}
}
int main()
{
std::vector<chuoi> a;
a.reserve(Max);
readStr(a);
writeStr(a);
return 0;
}
To solve you immediate problem, minimal changes in the code can be made as follows;
void readStr()
{
int i = 0;
while ( fgets(a[i].word, 10, stdin) != NULL)
{
a[i].word[strlen(a[i].word) - 1] = '\0'; // transform the end of line character to NULL
if (strlen(a[i].word) == 0) {
break;
}
i++;
}
}
If the standard input will always be used (stdin), the gets function can also be used;
while ( gets(a[i].word) != NULL)
{
if (strlen(a[i].word) == 0) {
break;
}
i++;
}
Notes;
fgets reads until the "enter" key on the stdin but includes the new line character
gets also reads until the return, but excludes the new line character
Both functions NULL terminate the input
Be careful of the form of gets it does not check for buffer overflow conditions
I would do something like this:
#include <string>
#include <iostream>
int main()
{
std::string line; // will contain each line of input
// Stop when line is empty or when terminal input has an error
while(std::getline(std::cin, line) && !line.empty())
{
// do stuff with line
}
}

segmentation fault(core dumped) in C dealing with getchar

I try to read a formula full of -,(,),|,&,>,= characters. I want to skip the blanks and end-of-line characters and put the others in an array to use them efficiently.
The code is:
int main()
{
char *array;
int i=0,j;
char c=getchar();
array=(char*)malloc(sizeof(char));
while (c != EOF)
{
if( islower(c) || (c!=' ' && c!='\n'))
{
array[i]=c;
i++;
array=(char*)realloc(array,sizeof(char)*(i+1));
}
}
}
My input is:
-(-(a&k) > ( -((a|-k)
|c ))
but it gives me segmentation fault. What should I do?
The problem is that you are managing memory yourself and that you are never changing the value of c which, if it's originally different from EOF, will cause an infinite loop. Use std::string:
int main() {
std::string array;
char c = getchar();
while (c != EOF) {
if(islower(c) || (c!=' ' && c!='\n'))
array.push_back(c);
c = getchar();
}
}
Live demo
Not only this is easier to read and to write, but it is also much more efficient than keep reallocating memory at every loop.
for C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main(){
char *array;
int ch, i=0, capacity = 16;
array = malloc(capacity);
while(EOF!=(ch = getchar())){//It is necessary to receive an int return value is in order to properly compare EOF.
if(!isspace(ch)){//islower not necessary when OR(||) condition
array[i++]=ch;
if(i==capacity)//Efficiency is not good of character by character
array = realloc(array, capacity += 16);
}
}
array[i] = '\0';
printf("%s\n", array);
free(array);
return 0;
}