getline() and char array - c++

I am so sorry, I know this is a basic problem, but I couldn't find an answer anywhere. Maybe I didn't realize the key word. The problem is:
I want to get inputs from user, which will be stored in the check[] array, then I see through it to get if inputs are valid or invalid (valid if it is like SpaceSpace+0000[i=1-5]).
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iomanip>
#include <string>
#include <cstring>
void main(){
char check[7];
for(i=0;i<7;i++){
check[i]='1';
};
//int check[4];
cin.getline(check,4);
bool cond=1;
for(i=0;i<7;i++){
cout<<check[i];
};
}
But when I print (cout) the array, I realized this: Input is 33, array[] is "33'Space'1111", my question here is what does the space in output mean and how could I deal with it(ignore, remove or anything).

The problem is that istream::getline reads the input, and then write a null-terminated byte string to your array.
What you see as a "space" is simply the null-terminator '\0'.
If you want to read raw unformated characters, use a loop to read one character at a time instead (checking for eof and newline):
char ch;
// Read up to four character, or until there's an error or end-of-file,
// or until you get a newline
for (unsigned i = 0; i < 4 && cin.get(ch) && ch != '\n'; ++i)
{
check[i] = ch;
}

Related

C++ add x amount of chars to string array

I have an array that holds strings. I was wondering if there's any way to add X amount of chars to the string in the array.
For example if a user inputs the number 10 and then the letter A, I want stringarray[x] to have the value of AAAAAAAAAA.
At the moment I am using a for-loop but I was wondering if there is an easier and more efficient way of doing this. One that doesn't require a loop.
#include <iostream>
#include <string>
#include <cctype>
#include <cmath>
#include <fstream>
using namespace std;
int main(){
char letter;
int number;
string stringarray[5] = {" "};
cin >> letter; // letter to add
cin >> number; // number of times
cout << stringarray[1]; // here I want the result to be letter x number
return 0;
}
I can only use these libraries.
I don't think it's necessary to post my for-loop since it already works. I am only wondering if there's any way to do it without the loop.
A C++ way of doing this is to use std::string s(10, 'A'); and get const char *stringarray = s.c_str() from it if you need a const char *.

Strncpy Causing Segmentation Fault c++

I have a c++ program which reads a text file and then converts that text file to a string. Then, it converts the string to a character array using strncpy. I have already seen the stackoverflow question on strncpy and taken the necessary precautions in order to avoid the issues it causes when creating the array. Could someone please explain why it still causes a stack error.
#include <iostream>
#include <string.h>
#include <random>
#include <fstream>
#include <istream>
#include <sstream>
#include <stdio.h>
using namespace std;
int main()
{
//open a stream reader
ifstream fin;
//opens the text file in the stream reader
fin.open("songlyrics.txt");
//will be used to aggregate all characters in text file
string song;
//used as a pointer when reading each character in text file
char ch;
//while the end of file is not reached
while(!fin.eof())
{
//get the character from the file and add it to the song string
fin.get(ch);
song += ch;
}
//close the file
fin.close();
//make a character array called lyrics_ with a length of the length of song
char lyrics_[song.length()];
//use strncpy to convert song to a char array, lyrics_
strncpy(lyrics_, song.c_str(), sizeof(lyrics_));
//avoid the segmentation fault
lyrics_[sizeof(lyrics_) - 1] = 0;
cout<<lyrics_;
return 0;
}
This:
char lyrics_[song.length()];
// ^^^^^^^^^^^^^
// not a compile-time constant
Is a variable-length array, and is not standard C++.
Also, you don't need to convert a std::string to a character array. It kind of already is:
char* lyrics = &song[0]; // assuming you don't append to song in the future
If you really want a separate character buffer, you'll have to allocate it dynamically:
char* lyrics = new char[song.length() + 1];
memcpy(lyrics, song.c_str(), song.length() + 1); // this will copy the null terminator
delete [] lyrics; // don't forget this
C++ does not support the variable length array feature from C. VLA was a standard feature of C.1999, and an optional feature in C.2011.
If you want to make a copy of the contents of a string into a dynamically sized array of char, you can use a vector:
std::vector<char> lyrics_(song.begin(), song.end());
lyrics_.push_back('\0');
std::cout << &lyrics_[0];

fstream's getline() works for a little bit...and then breaks

I have a text file with a bunch of numbers separated by newlines, like this:
123.25
95.12
114.12 etc...
The problem is, when my program reads it, it only copies the number to the array up to the second number and then fills the rest of the elements with zeroes. I've tried using delimiters and ignore statements but nothing has worked. Here's the code.
Edit(here's the whole program:)
#include <iostream>
#include <string.h>
#include <iomanip>
#include <fstream>
using namespace std;
struct utilityInfo
{
char utility[20];
double monthlyExpenses[12];
};
int main(){
utilityInfo Utility[3];
char charray[100];
fstream inFile;
inFile.open("expenses.txt");
inFile.getline(charray, 7);
cout<<charray<<endl;
if(inFile.fail()) cout<<"it didnt work";
for(int i=0; i<12; i++)
{
inFile.getline(charray,20);
Utility[0].monthlyExpenses[i]=atof(charray);
}
for(int z=0; z<12; z++)
{
cout<<Utility[0].monthlyExpenses[z]<<endl;
}
inFile.close();
return 0;
}
Here's what the text file looks like:
207.14
177.34
150.55
104.22
86.36
53.97
52.55
58.77
64.66
120.32
153.45
170.90
And here's what the output looks like:
207.14
177.34
0
0
0
0
0
0
0
0
0
0
Your first entry in your file, "207.14" is actually "207.14 " -- (there's a space there). You read 7 characters but leave " " there, this means that istream::getline sets the failbit on inFile, meaning your successive getlines fail.
To fix this either read enough to reach the newline character, remove the space and/or clear inFiles failbit after your first getline.
You should also add a check within your for loop to handle any errors that may occur with fail/bad/eof bits.

How to display an integer literally as a character

I have an integer 1 and i want to display it as a character '1' in C++. So far I have only managed to convert it from say integer 65 to character 'A'.
How do you stop this ?
int theDigit = 1;
char ch = theDigit+'0';
This works because it's guaranteed1 that the sequence of characters '0'...'9' is contiguous, so if you add your number to '0' you get the corresponding character. Obviously this works only for single digits (if theDigit is e.g. 20 you'll get an unrelated character), if you need to convert to a string a whole number you'll need snprintf (in C) or string streams (in C++).
C++11, [lex.charset] ΒΆ3:
In both the source and execution basic character sets, the value of each character after 0 in the above list of decimal digits shall be one greater than the value of the previous.
By the way, I suppose that they didn't mandate contiguity also in the alphabetical characters just because of EBCDIC.
Use the stringstream.
int blah = 356;
stringstream ss;
string text;
ss << blah;
ss >> text;
Now text contains "356"(without quotes). Make sure to include the header files and use the namespace if you are going to copy my code:
#include <sstream> //For stringstream
#include <string>
using namespace std;
#include <stdio.h>
#include <stdlib.h>
int i = 3;
char buffer [25];
itoa (i, buffer, 10);
printf ("Integer: %s\n",buffer);
Integer: 3
You did just ask about printing an integer, so the really simple c++ answer is:
#include <iostream>
int main()
{
int value = 1;
std::cout << value << endl;
return 0;
}

How do i read just a single whitespace only from stdin/cin in C++?

I'm having trouble translating the following piece of Java code into its C++ equivalent, meant to be a simple routine to parse an input stream:
String word = br.readLine();
Given a sample input file, with the contents displayed in hex by piping through od -bc, the following is obtained:
...
0000020 040 012 ...
\n
...
indicating that I've made the input file correctly, by supplying on this one line a space character, following a newline character.
Java is able to read in the entire string a '<space>\n', but the C++ functions like fgets(), sscanf(), getchar()..., and their equivalent family of functions, all fail to detect this space rather than ignoring it, so instead i'm returned a zero-length string.
What is the idiomatic way to do this?
My g++ compiler details:
Target: i686-apple-darwin11
Thread model: posix
gcc version 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.1.00)
Code + Sample input (mirrored # https://gist.github.com/1933400)
#include <tr1/unordered_map>
#include <stdio.h>
#include <cstdio>
#include <iostream>
#include <cassert>
#include <algorithm>
#include <string>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <vector>
#include <string.h>
#include <ctime>
#include <stdlib.h>
#include <math.h>
#include <string>
#include <locale>
#include <sys/time.h>
#include <iterator>
using namespace std;
#define REP(i, a, b) for(int i=int(a); i<int(b); ++i)
const int MAX_WORD_LENGTH = 22;
char word[MAX_WORD_LENGTH];
string sz_word;
int N, M;
int main()
{
scanf("%d %d\n", &N, &M);
REP(i,0,N)
{
memset(word, 0, MAX_WORD_LENGTH);
scanf("%s\n", word);
//if (i == N-1)
// cout << word << endl;
}
REP(i,0,M)
{
std::getline(std::cin, sz_word);
cout << "word: '" << sz_word << "'" << endl;
}
return 0;
}
Sample input:
1 1
1
<space>
The C++ equivalent is (assuming br is some kind of std::istream):
std::string word;
std::getline(br, word);
If you're reading from standard input:
std::getline(std::cin, word);
The functions you list are all C functions; they're available in C++ if you really want them, but the C++ library is usually more convenient.
UPDATE: having seen your real code, the problem is that you're mixing C and C++ style input; this is usually a bad idea, and requires some care to get it right if you really have to. The problems are:
\n on the end of the scanf strings will match any amount of whitespace; it will keep matching any newlines until you enter something other than whitespace. Just remove the \n.
After the last scanf, there is still an unmatched \n in the input stream, so the first getline will give an empty line. You can call std::cin.ignore() to skip that newline.
The best solution would be to use std::cin for all input, and not try to use the <cstdio> functions at all. You can read numbers using the formatted extraction operator: std::cin >> N >> M;
If I may simplify your program and restate your question:
#include <cstdio>
#include <iostream>
#include <string>
char word[22];
std::string sz_word;
int main()
{
std::scanf("%s\n", word);
std::cout << "'" << word << "'" << std::endl;
std::getline(std::cin, sz_word);
std::cout << "word: '" << sz_word << "'" << std::endl;
return 0;
}
An appropriate input is this:
11
22
Note the space at the beginning of the 2nd line. The expected output is:
'11'
word: ' 22'
The observed output is:
'11'
word: '22'
Now then, why is the expected output different from the observed output?
Answer: Because you called scanf. From the Linux man page:
The format string consists of a sequence of directives ...A directive is one of the following ...
A sequence of white-space characters (space, tab, newline, etc.; see isspace(3)). This directive matches any amount of white space, including none, in the input.
So, the \n in your scanf format string matches any amount of white space, including the initial white space on the subsequent line.
fgets() really should work, it's not documented as "eating" white space, it even includes the line feed in the returned string.
Well something that could help solve your problem with the reading in whitespace.
char space[1];
// then set the character to either a NULL or to a basic ' ' <space>
SO. for example with your code instead of calling the scanf() I would instead make a constructor or just a setSpace() type function. Strings can be really messy so I would also get rid of those if at all possible.
Hope this maybe at least inspires some thought somewhere...