int main(int argc, const char * argv[])
{
ifstream input;
input.open("test.txt");
string arrAtoms[700];
string temp;
int i = 0;
while(getline(input, temp)){
if(startsWithAtom(temp)) {
arrAtoms[i] = temp;
i++;
}
}
return 0;
}
bool startsWithAtom(string test) {
string atom = "ATOM";
if(test.find(atom) == 0) {
return true;
}
return false;
}
So this is my code to read a line and store it in arrAtoms[] if it starts with "ATOM".
For some reason, I keep getting the error Thread1: EXC_BAD_ACCESS(code=EXC_1386_GPFLT)
and I have no clue why. Please help!
The code runs quite fine on my machine. Maybe the problem is that the file has more ATOM entries than 700? And your string array can only containg 700. If you don't know how many entries there will be, try using a vector
This is the file I tested the code on:
soadiaodiaodsa
sdaiod sadoiasoda
ATOM alodaskd
ATOM alosad
ATOM lol
saodai aosdisoad daiosiadsa
ATOM ATOM ATOM
ATOM LOL test
lololololol
I also tried outputting the first 15 entries in the array and it works fine and consists only of lines starting with ATOM:
for(unsigned int i=0;i<15;i++)
cout << arrAtoms[i] << endl;
You are using array with length 700. If your file have more than 700 lines that start with "ATOM", a memory allocation error will happen. A better way to do this is to use vector, so you don't need to worry about the size of the file.
#include <vector>
int main(int argc, const char * argv[])
{
ifstream input;
input.open("test.txt");
std::vector <string> arrAtoms;
string temp;
while(getline(input, temp)){
if(startsWithAtom(temp)) {
arrAtoms.push_back(temp);
}
}
return 0;
}
Related
I'm having slight trouble creating a 2D Vector of String that's created by reading values from a text file. I initially thought I needed to use an array. however I've come to realise that a vector would be much more suited to what I'm trying to achieve.
Here's my code so far:
I've initialised the vector globally, but haven't given it the number of rows or columns because I want that to be determined when we read the file:
vector<vector<string>> data;
Test data in the file called "test" currently looks like this:
test1 test2 test3
blue1 blue2 blue3
frog1 frog2 frog3
I then have a function that opens the file and attempts to copy over the strings from text.txt to the vector.
void createVector()
{
ifstream myReadFile;
myReadFile.open("text.txt");
while (!myReadFile.eof()) {
for (int i = 0; i < 5; i++){
vector<string> tmpVec;
string tmpString;
for (int j = 0; j < 3; j++){
myReadFile >> tmpString;
tmpVec.push_back(tmpString);
}
data.push_back(tmpVec);
}
}
}
However, when I attempt to check the size of my vector in my main function, it returns the value '0'.
int main()
{
cout << data.size();
}
I think I just need a pair of fresh eyes to tell me where I'm going wrong. I feel like the issues lies within the createVector function, although I'm not 100% sure.
Thank you!
You should use std::getline to get the line of data first, then extract each string from the line and add to your vector. This avoids the while -- eof() issue that was pointed out in the comments.
Here is an example:
#include <string>
#include <iostream>
#include <vector>
#include <sstream>
typedef std::vector<std::string> StringArray;
std::vector<StringArray> data;
void createVector()
{
//...
std::string line, tempStr;
while (std::getline(myReadFile, line))
{
// add empty vector
data.push_back(StringArray());
// now parse the line
std::istringstream strm(line);
while (strm >> tempStr)
// add string to the last added vector
data.back().push_back(tempStr);
}
}
int main()
{
createVector();
std::cout << data.size();
}
Live Example
I am trying to read in the first 7 chars of a file named "board.txt" into a vector<'char> but I am having issues for some reason. I am not too familiar with C++ so any advice would be appreciated, here is the code I have so far
//rack
int charCount = 0;
char ch;
ifstream rackIn("board.txt");
while(rackIn.get(ch) && charCount < 7){
this->getMyRack().push_back(ch);
}
And here is the function getMyRack used in the code above:
vector<char> board::getMyRack(){
return this->myRack;
}
myRack is a char vector
I tried to test this in my main using this:
for (int i = 0; i < test->getMyRack().size(); ++i){
cout << test->getMyRack().at(i);
}
but it does not output anything, why are the chars i am reading in not being added into my char vectors?
Because you don't put char in your vector. Your function getMyRack() returns vector but not address of your vector. You can add method to your class board for adding char, for example:
void board::addChar(char c){
this->myRack.push_back(c);
}
And then call this function:
while(rackIn.get(ch) && charCount < 7){
this->addChar(ch);
}
Or change the return type of your function.
read line one or (how much lines required) from file to a string
create substring of 7 chars from beginning
std::ifstream file("board.txt");
std::string str;
// to read single line
std::getline(file, str);
// to read 7 chars
str= str.substr(0,7);
vector<char> char_buf;
for(size_t i =0; i <= str.size();i++)
{
char_buf.push_back(str[i])
}
// use the char_buf
easier or second way is use
#include<fstream> // for ifstream
#include <cstdlib> // for exit()
std::string file_name ="board.txt";
std::ifstream input_stream;
std::vector<char> char_buf;
input_stream.open(file_name);
if(input_stream.fail()) { exit(0);}
int char_no=0;
while(i<=7)
{
char c = input_stream.get();
char_buf.push_back(c);
i++;
}
// use char_buf
std::string str;
int char_count=0;
// Read the next line from File untill it reaches the 7.
while (std::getline(in, str)&& char_count!=7)
{
// Line contains string of length > 0 then save it in vector
if (str.size() > 0)
your_char_vector.push_back(str);
char_count++;
if(char_count==7)
break;
}
What I've been trying to do is...
1) to read txt files by command line argument,
2) to use strings in the txt files as arguments for the main method (or whatever method you need to invoke).
For example, there are two txt files, one of which is named character.txt and the other match.txt.
The contents of the files would be like this.
character.txt
//This comprises of six rows. Each of the rows has two string values
Goku Saiyan
Gohan Half_Saiyan
Kuririn Human
Piccolo Namekian
Frieza villain
Cell villain
match.txt
//This comprises of three rows, each of them is one string value
Goku Piccolo
Gohan Cell
Kuririn Frieza
If I use those strings without using command line, I'd declare the strings in character.txt like this.
typedef string name; //e.g. Goku
typedef string type; //e.g. Saiyan, Human, etc
Now I'm looking for how to read and send string values from txt files like the ones above, and to use them for functions inside the main method, ideally like this way.
int main(int argc, char *argv)
{
for (int i = 1; i < argc; i++) {
String name = *argv[i]; //e.g. Goku
String type = *argv[i]; //e.g. Saiyan, Human, etc
String match = * argv[i]; //Goku Piccolo
//I don't think any of the statements above would be correct.
//I'm just searching for how to use string values of txt files in such a way
cout << i << " " << endl; //I'd like to show names, types or matchs inside the double quotation mark.
}
}
Ideally, I'd like to invoke this method in this way.
According to this web site., at least I understand it is possible to use command line arguments with C++, but I cannot find any more information. I'd appreciate if you'd give any advice on it.
PS. I'm using Windows and Code Blocks.
Asuming you just want to read contents of the files and process it, you can start with this code (Without any errors checks tho). It simply gets filenames from command line and reads file contents into 2 vectors. Then you can just process these vectors as u need.
#include <string>
#include <fstream>
#include <iostream>
#include <vector>
std::vector<std::string> readFileToVector(const std::string& filename)
{
std::ifstream source;
source.open(filename);
std::vector<std::string> lines;
std::string line;
while (std::getline(source, line))
{
lines.push_back(line);
}
return lines;
}
void displayVector(const std::vector<std::string&> v)
{
for (int i(0); i != v.size(); ++i)
std::cout << "\n" << v[i];
}
int main(int argc, char **argv)
{
std::string charactersFilename(argv[1]);
std::string matchesFilename(argv[2]);
std::vector<std::string> characters = readFileToVector(charactersFilename);
std::vector<std::string> matches = readFileToVector(matchesFilename);
displayVector(characters);
displayVector(matches);
}
to see how to use command line arguments look at this.
http://www.cplusplus.com/articles/DEN36Up4/
you cannot use the contents of the file which you have passed to your app through command line arguments. only the name of the file is passed to the app.
you should open the file using that name and read its contents. take a look at this:
http://www.cplusplus.com/doc/tutorial/files/
First the main function prototype should be
int main(int argc, char **argv)
OR
int main(int argc, char *argv[])
Second after retrieving files names in the main function you should open each file and retrieve its contents
Third Sample code
int main(int argc, char* argv[])
{
for(int i=1; i <= argc; i++) // i=1, assuming files arguments are right after the executable
{
string fn = argv[i]; //filename
cout << fn;
fstream f;
f.open(fn);
//your logic here
f.close();
}
return 0;
}
You define main prototype incorrectly. You also need std::ifstream to read files.
If you expect exactly two arguments, you may check argc and extract arguments directly:
int main(int argc, char* argv[]) {
if(argc != 3) {
std::cerr << "Usage: " << argv[0]
<< " name.txt match.txt" << std::endl;
return 1;
}
std::ifstream name_file(argv[1]);
std::ifstream match_file(argv[2]);
// ...
return 0;
}
If you expect unspecified number of files, than you need a loop and an array to save them, i.e. vector:
int main(int argc, char* argv[]) {
std::vector<std::ifstream> files;
for(int i = 1; i < argc; ++i)
files.emplace_back(argv[i]);
// ...
return 0;
}
And do not forget to check if files are openable.
#include<stdio.h>
#include<stdlib.h>
int main(int argc, char *argv[])
{
FILE *fp = fopen( argv[1], "r");
char line[50];
if (fp == NULL)
{
printf("File opening Unsuccessful\n");
exit(1);
}
while (fgets(line , 30 , fp) != NULL)
{
printf("%s",line);
}
fclose(fp) ;
return 0;
}
I'm having trouble reading a number list from a .txt file to a dynamic array of type double. This first number in the list is the number of numbers to add to the array. After the first number, the numbers in the list all have decimals.
My header file:
#include <iostream>
#ifndef SORT
#define SORT
class Sort{
private:
double i;
double* darray; // da array
double j;
double size;
public:
Sort();
~Sort();
std::string getFileName(int, char**);
bool checkFileName(std::string);
void letsDoIt(std::string);
void getArray(std::string);
};
#endif
main.cpp:
#include <stdio.h>
#include <stdlib.h>
#include "main.h"
int main(int argc, char** argv)
{
Sort sort;
std::string cheese = sort.getFileName(argc, argv); //cheese is the file name
bool ean = sort.checkFileName(cheese); //pass in file name fo' da check
sort.letsDoIt(cheese); //starts the whole thing up
return 0;
}
impl.cpp:
#include <iostream>
#include <fstream>
#include <cstring>
#include <stdlib.h>
#include "main.h"
Sort::Sort(){
darray[0];
i = 0;
j = 0;
size = 0;
}
Sort::~Sort(){
std::cout << "Destroyed" << std::endl;
}
std::string Sort::getFileName(int argc, char* argv[]){
std::string fileIn = "";
for(int i = 1; i < argc;)//argc the number of arguements
{
fileIn += argv[i];//argv the array of arguements
if(++i != argc)
fileIn += " ";
}
return fileIn;
}
bool Sort::checkFileName(std::string userFile){
if(userFile.empty()){
std::cout<<"No user input"<<std::endl;
return false;
}
else{
std::ifstream tryread(userFile.c_str());
if (tryread.is_open()){
tryread.close();
return true;
}
else{
return false;
}
}
}
void Sort::letsDoIt(std::string file){
getArray(file);
}
void Sort::getArray(std::string file){
double n = 0;
int count = 0;
// create a file-reading object
std::ifstream fin;
fin.open(file.c_str()); // open a file
fin >> n; //first line of the file is the number of numbers to collect to the array
size = n;
std::cout << "size: " << size << std::endl;
darray = (double*)malloc(n * sizeof(double)); //allocate storage for the array
// read each line of the file
while (!fin.eof())
{
fin >> n;
if (count == 0){ //if count is 0, don't add to array
count++;
std::cout << "count++" << std::endl;
}
else {
darray[count - 1] = n; //array = line from file
count++;
}
std::cout << std::endl;
}
free((void*) darray);
}
I have to use malloc, but I think I may be using it incorrectly. I've read other posts but I am still having trouble understanding what is going on.
Thanks for the help!
Your use of malloc() is fine. Your reading is not doing what you want it to do.
Say I have the inputfile:
3
1.2
2.3
3.7
My array would be:
[0]: 2.3
[1]: 3.7
[2]: 0
This is because you are reading in the value 1.2 as if you were rereading the number of values.
When you have this line:
fin >> n; //first line of the file is the number of numbers to collect to the array
You are reading in the count, in this case 3, and advancing where in the file you will read from next. You are then attempting to reread that value but are getting the first entry instead.
I believe that replacing your while() {...} with the code below will do what you are looking for.
while (count != size && fin >> n)
{
darray[count++] = n; //array = line from file
std::cout << n << std::endl;
}
This should give you the correct values in the array:
[0]: 1.2
[1]: 2.3
[2]: 3.7
You appear to be writing the next exploitable program. You are mistakenly trusting the first line of the file to determine your buffer size, then reading an unlimited amount of data from the remainder of the file into a buffer that is not unlimited. This allows an evil input file to trash some other memory in your program, possibly allowing the creator of that file to take control of your computer. Oh noes!
Here's what you need to do to fix it:
Remember how much memory you allocated (you'll need it in step #2). Have a variable alleged_size or array_length that is separate from the one you use to read the rest of the data.
Don't allow count to run past the end of the array. Your loop should look more like this:
while ((count < alleged_size) && (cin >> n))
This both prevents array overrun and decides whether to process data based on whether it was parsed successfully, not whether you reached the end-of-file at some useless point in the past.
The less problematic bug is the one #bentank noticed, that you didn't realize that you kept your position in the file, which is after the first line, and shouldn't expect to hit that line within the loop.
In addition to this, you probably want to deallocate the memory in your destructor. Right now you throw the data away immediately after parsing it. Wouldn't other functions like to party on that data too?
For Example:
If I need to read a multiple line input like(and I dont know How many lines would be there!!):
1 20
2 31
3 41
I am using something like
int main()
{
string line;
while(getline(cin,line) != NULL)
{
// some code
// some code
}
}
Now the program never stops- i.e always it expects some input. How do i beak the loop when there are no more input lines ?
Just test the variable line for empty each time you read a line. If the use presses enter with no other data, then line will be empty.
#include <iostream>
#include <string>
using std::cin;
using std::getline;
using std::string;
int main(int argc, char *argv[]) {
string line;
while (true) {
getline(cin, line);
if (line.empty()) {
break;
}
// some code
}
return 0;
}
Note that the use of scanf directly on stdin is not very safe. For example, entering anything that can't be parsed as a number will make the loop hang. Here's a more robust implementation that reads whole lines first and then tries to parse the numbers from it.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char * line = NULL;
size_t sz = 0;
while(!feof(stdin)) {
ssize_t ln = getline(& line, & sz, stdin);
if(ln > 0) {
int x, y;
if(sscanf(line, "%d %d", & x, & y) == 2)
printf("x = %i, y = %i\n", x, y);
else
puts("invalid input");
}
}
return EXIT_SUCCESS;
}
Just insert a special end-of-input command, and parse the rest line-by-line. You can't automatically detect end-of-input, because there's no way to know if the user is genuinely finished inputting or just browsing or speaking or whatever- it's a totally system-external circumstance.
On linux - C-d (or Ctrl+D) outputs the EOF character, which will terminate your loop.
It's much easier to do something like...
~ $ cat sample.input | my_cool_program
output will be displayed here.
while (true)
{
long value1;
long value2;
int nofValuesRead;
nofValuesRead = scanf("%ld %ld\n",&value1,&value2);
if (nofValuesRead==0) break;
if (nofValuesRead>=1)
{
// Process value1
}
if (nofValuesRead>=2)
{
// Process value2
}
}