gone
gone

Reputation: 2627

Trouble with C++ file I/O

Noobie Alert. Ugh. I'm having some real trouble getting some basic file I/O stuff done using <stdio.h> or <fstream>. They both seem so clunky and non-intuitive to use. I mean, why couldn't C++ just provide a way to get a char* pointer to the first char in the file? That's all I'd ever want.

I'm doing Project Euler Question 13 and need to play with 50-digit numbers. I have the 150 numbers stored in the file 13.txt and I'm trying to create a 150x50 array so I can play with the digits of each number directly. But I'm having tons of trouble. I've tried using the C++ <fstream> library and recently straight <stdio.h> to get it done, but something must not be clicking for me. Here's what I have;

#include <iostream>
#include <stdio.h>
int main() {

const unsigned N = 100;
const unsigned D = 50; 

unsigned short nums[N][D];

FILE* f = fopen("13.txt", "r");
//error-checking for NULL return

unsigned short *d_ptr = &nums[0][0];
int c = 0;
while ((c = fgetc(f)) != EOF) {
    if (c == '\n' || c == '\t' || c == ' ') {
        continue;
    }   
    *d_ptr = (short)(c-0x30);
    ++d_ptr;
}   
fclose(f);
//do stuff
return 0;
}

Can someone offer some advice? Perhaps a C++ guy on which I/O library they prefer?

Upvotes: 0

Views: 175

Answers (3)

Ben Voigt
Ben Voigt

Reputation: 283803

Here's a nice efficient solution (but doesn't work with pipes):

std::vector<char> content;
FILE* f = fopen("13.txt", "r");
// error-checking goes here
fseek(f, 0, SEEK_END);
content.resize(ftell(f));
fseek(f, 0, SEEK_BEGIN);
fread(&content[0], 1, content.size(), f);
fclose(f);

Here's another:

std::vector<char> content;
struct stat fileinfo;
stat("13.txt", &fileinfo);
// error-checking goes here
content.resize(fileinfo.st_size);
FILE* f = fopen("13.txt", "r");
// error-checking goes here
fread(&content[0], 1, content.size(), f);
// error-checking goes here
fclose(f);

Upvotes: 1

razeh
razeh

Reputation: 2765

Rather than reading the one hundred 50 digit numbers from a file, why not read them directly in from a character constant?

You could start your code out with:

static const char numbers[] = 
 "37107287533902102798797998220837590246510135740250"
 "46376937677490009712648124896970078050417018260538"...

With a semicolon at the last line.

Upvotes: 0

Jerry Coffin
Jerry Coffin

Reputation: 490623

I would use an fstream. The one problem you have is that you obviously can't fit the numbers in the file into any of C++'s native numeric types (double, long long, etc.)

Reading them into strings is pretty easy though:

std::fstream in("13.txt");

std::vector<std::string> numbers((std::istream_iterator<std::string>(in)),
                                  std::istream_iterator<std::string>());

That will read in each number into a string, so the number that was on the first line will be in numbers[0], the second line in numbers[1], and so on.

If you really want to do the job in C, it can still be quite a lot easier than what you have above:

char *dupe(char const *in) {
    char *ret;
    if (NULL != (ret=malloc(strlen(in)+1))
        strcpy(ret, in);
    return ret;
}

// read the data:
char buffer[256];
char *strings[256];
size_t pos = 0;

while (fgets(buffer, sizeof(buffer), stdin)
    strings[pos++] = dupe(buffer);

Upvotes: 1

Related Questions