0

I've been trying to solve this problem without using pointers, only with the basics (I'm a student) but I can't fine the solution.

void ReverseFile() {

FILE *originalM, *fin;

fopen_s(&originalM, "original.txt", "r");
fopen_s(&fin, "inverted.txt", "w");

char arr[100];

for (int i = 0; i < 100 && !feof(originalM); i++)
{
    fscanf_s(originalM, "%c ", &arr[i]);
    cout << arr[i] ;
}
cout << endl;
fclose(originalM);

for (int i = 0, k = 100; i < 100; i++, k--) 
{
    arr[k] = arr[i];
    cout << arr[k];
}
fclose(fin);}

So far I have this function and one file of text (originalM.txt) which contains chars (with a space in between):

e e a a e e a a e e a a

In the first loop I get each char of the file and save it in the array. The problem comes in the second loop, where I want to reverse them. How can I solve this? I was trying to create a new array and store the chars but that doesn't work. Also I was trying to print it into the new file with this:

fprintf(fin, "%c ", &arr[k]);

I will be grateful for any help.

Rama
  • 3,222
  • 2
  • 11
  • 26
Kamelo10
  • 33
  • 8
  • Are you happy to use std::reverse? – UKMonkey Jan 31 '17 at 14:17
  • 2
    You've tagged both C and C++ . They are different languages. – pinkfloydx33 Jan 31 '17 at 14:17
  • you write in the same array. and @YuriyIvaskevych this can not be C because C has no `cout` – Kami Kaze Jan 31 '17 at 14:18
  • @UKMonkey Umm interesting, sure. – Kamelo10 Jan 31 '17 at 14:20
  • 1
    Have you heard of `std::vector`? – StoryTeller - Unslander Monica Jan 31 '17 at 14:20
  • @pinkfloydx33 Fixed, sorry. – Kamelo10 Jan 31 '17 at 14:20
  • @KamiKaze I know that, but pointing out to the OP that they are different. – pinkfloydx33 Jan 31 '17 at 14:21
  • @StoryTeller Yes but i can't use it in this function... (It's a requirement of the teacher) – Kamelo10 Jan 31 '17 at 14:23
  • Start with finding a better teacher. Particularly one that doesn't think this sort of crippling requirement is "teaching you the real C++". – StoryTeller - Unslander Monica Jan 31 '17 at 14:25
  • @StoryTeller I'd wager on this level it is not about teaching you real C++ but just trying to get them wrap their head around programming. Which is more than enough to my mind as general programming education should not go into the depths of language specifics – Kami Kaze Jan 31 '17 at 14:30
  • @StoryTeller Hahaha okey, anyway I will be grateful if you help me with the vector. – Kamelo10 Jan 31 '17 at 14:32
  • 1
    @KamiKaze - I consider the attitude that forces pupils to use the `cstring` library instead of `std::string` as the exact opposite. They don't get to just "wrap their head around programming" because they constantly need to chase the very intricate details you claim they are sheltered from. It's much more intuitive to do `std::string str = "Hello World";` than wonder why your program segfaults after you defined `char *str = "Hello World!";` – StoryTeller - Unslander Monica Jan 31 '17 at 14:36
  • @StoryTeller well I exactly disagree with that way, because (given it was explained beforehand) the more basic handling of arrays/pointers gives more insight to the basics. After they grasped the basic concepts you can move on to use such things from `std`. And `std::string` wouldn't help you if would want to rearrange an integer array. So a small modification will hand you the same problem again – Kami Kaze Jan 31 '17 at 14:54

5 Answers5

4

In C++ and by using vector and stream iterators, you can do this (generalized for arbitrary number of characters):

void reverseFile(const string& in, const string& out)
{
    ifstream input(in);
    ofstream output(out);
    istream_iterator<char> inStart(input), inEnd;
    // load from the input file
    vector<char> data(inStart, inEnd);
    // copy back to the output file in reversed order
    copy(data.rbegin(), data.rend(), ostream_iterator<char>(output));
}

If you'd like to retain the spaces in between the characters, the ostream_iterator also supports a delimiter parameter, so to retain spaces, you can simply add it to the line:

copy(data.rbegin(), data.rend(), ostream_iterator<char>(output, " "));
EmDroid
  • 5,918
  • 18
  • 18
2

You can use std::reverse to reverse arr in-place. Unless you're always sure that all 100 values of arr will contain meaningful values, you need to keep track of how many values you read.

Everything becomes trivial when you use idiomatic C++:

void ReverseFile() 
{
    std::ifstream ifs{"original.txt"};

    // Read from `ifs` into a `arr` vector.
    // (From "http://stackoverflow.com/questions/7241871").
    std::ostringstream oss;
    ss << file.rdbuf();
    const auto& s = ss.str();
    std::vector<char> arr(s.begin(), s.end());

    // Reverse `arr` in place:
    std::reverse(std::begin(arr), std::end(arr));

    // Save `arr` to file.
    std::ofstream ofs{"inverted.txt"};
    for(auto x : arr) ofs << x;
    ofs.flush(); 
    ofs.close();
} 
Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416
  • There is another way instead of using for(auto)? I can do it just with a normal for right? – Kamelo10 Jan 31 '17 at 14:29
  • @Kamelo10: yes, but why would you want to? – Vittorio Romeo Jan 31 '17 at 14:32
  • Hmm... why the assumption the entire 100 characters are read? – StoryTeller - Unslander Monica Jan 31 '17 at 14:43
  • @StoryTeller: the incorrect loop that was meant to reverse the values in OP's code was looping over all 100 elements, that's why I made the assumption. – Vittorio Romeo Jan 31 '17 at 14:45
  • @VittorioRomeo - The OP was wrong to make it. And answers would be wrong to maintain it. It's not just about showcasing shiny C++ features, after all. – StoryTeller - Unslander Monica Jan 31 '17 at 14:46
  • @StoryTeller: no need to be condescending. As I incorrectly assumed that the OP was interested in all `100` elements you should not assume that I simply want to *"showcase shiny C++ features"*. Also, considering `std::reverse` and range-`for` *"shiny C++ features"* instead of fundamental building block for programs is a counter-productive attitude. – Vittorio Romeo Jan 31 '17 at 14:49
  • I have nothing against the fundamental building blocks of software. A range based for is a nicety that is irrelevant to the correctness of the OP's code. Since your answer started with that, and originally completely overlooked the OP's bug, it's not a leap of me to say you missed the point by setting your sights on getting it to look like C++11 instead of just correct C++ in general. – StoryTeller - Unslander Monica Jan 31 '17 at 14:56
  • @StoryTeller: yes, I didn't think about the possibility of `arr` being only partially filled with meaningful values as I was misled by OP's second for loop's ranges. That was my mistake. Blaming that on my suggestion of using Modern C++ features is completely ridiculous though. – Vittorio Romeo Jan 31 '17 at 15:00
  • `for`-range loops are the default choice for me and should be the general default choice. I would have to use more of my brain processing power to suggest a non-range-`for` loop as there needs to be a good reason for that. Regardless, the OP didn't keep track of the number of read characters anywhere either, so I would have had to introduce a counter independently from my iteration construct choice. Therefore, my *"desire of showing shiny C++11 features*" has nothing to do with my wrong assumption *(which, obviously, was a mistake on my part)*. – Vittorio Romeo Jan 31 '17 at 15:03
  • I never postulated anything about your desires. I pointed out what I considered an error in the answers priorities. Seeing as it was all edited away, arguing about it further is moot. – StoryTeller - Unslander Monica Jan 31 '17 at 16:25
0

Okay, suppose you have read some string into array char arr[100];. Now to reverse it you can use something like this:

size_t length = strlen(arr);
for (int i = 0; i < length / 2; ++i)
{
    char swapChar = arr[i];
    arr[i] = arr[length-i-1];
    arr[length-i-1] = swapChar;
}

Instead of 3 statements inside of that for loop you can use std::swap:

std::swap(arr[i], arr[length-i-1]);

Another way is to use std::reverse as already answered by @VittorioRomeo.

Edit 1: Thanks to @StoryTeller for pointing out that your array should be NULL-terminated in order for strlen to work. So after you've read data (say l characters) do arr[l] = '\0';

Yuriy Ivaskevych
  • 956
  • 8
  • 18
  • Using `strlen` to get the length of a C-style array is a bad idea. You can statically get the size at compile-time using `sizeof` *(a better idea would be [using a template function](http://stackoverflow.com/a/18078435/598696))*. The rest of the answer is interesting for educational purpose but I would strongly recommend using `std::reverse` instead of reinventing the wheel. – Vittorio Romeo Jan 31 '17 at 14:38
  • 3
    Calling `strlen` is undefined behavior since the array is filed with indeterminate values, and the OP does not NUL terminate it. – StoryTeller - Unslander Monica Jan 31 '17 at 14:41
  • @VittorioRomeo Also `std::string` or `std::vector` could be used to store data. So back to `sizeof` - what if we read less characters that 100 (or whatever allocated size)? – Yuriy Ivaskevych Jan 31 '17 at 14:42
  • @StoryTeller yes, thanks for pointing that out, fixed and edited. – Yuriy Ivaskevych Jan 31 '17 at 14:48
0

You're using this code to reverse:

for (int i = 0, k = 100; i < 100; i++, k--) 
{
    arr[k] = arr[i];
    cout << arr[k];
}

Think of it. In first 50 iterations you rewrite first half of array with the data of a second part, mirrored, in second 50 iterations you rewrite the second part with what you have copied into the first. What you need here is:

for (int i = 0; i < 50; i++) 
{
    char tmp; //you can use std::swap instead.
    tmp = arr[i];
    arr[i] = arr[100-i];
    arr[100-i] = tmp;
}

Solutions like std::reverse are better, of course.

Leontyev Georgiy
  • 1,295
  • 11
  • 24
  • Okey I understand. – Kamelo10 Jan 31 '17 at 14:42
  • But... did you profile it? For only 100 characters the time difference should not be noticeable, but for greater sizes, your algorithm could break *locality* and make the hardware cache less useful, resulting in less efficient code. Always carefully profile all low level optimization attempts! – Serge Ballesta Jan 31 '17 at 14:49
0

Why not just save it in reverse order?

void ReverseFile() {
    FILE *originalM, *fin;
    fopen_s(&originalM, "original.txt", "r");
    fopen_s(&fin, "inverted.txt", "w");

    char arr[100];
    for (int i = 0; i < 100 && !feof(originalM); i++)
    {
        fscanf_s(originalM, "%c ", &arr[i]);
        cout << arr[i] ;
    }
    cout << endl;
    fclose(originalM);

    for (int k = i - 1, k >= 0; k--) 
    {
        cout << arr[k];
    }
    fclose(fin);
}
wmc
  • 98
  • 6