0
#include <iostream>
#include <string> 
#include <fstream>
using namespace std;
int main() {
char x[20];
cout << "enter something\n";
cin.getline(x,20);
ofstream o("d:/tester.txt");
//o.write( (char*)&x , sizeof(x) );
for(int i = 0 ; i<=19 ; i++ ) {
 o.put(x[i]);
}
}

I am not getting that output in the file the one which i enter during program . for eg. the output is 畳慨汩朠灵慴찀쳌쳌쳌 on writing suhail gupta.

What is the problem with the code ? Even when i use o.write( (char*)&x , sizeof(x) ); (the commented statement) i get the same output.

What is the reason?

Suhail Gupta
  • 22,386
  • 64
  • 200
  • 328

1 Answers1

3

Your program involves undefined behavior. The x array is not fully initialized and you read from the uninitialized indices. Besides, you always write 20 bytes, independent of what you read from the user.

I guess you use some text editor like Notepad. The latter has bugs when trying to guess the encoding. It appears that it guesses the file is UTF16 and displays 20/2 == 10 characters instead.

To solve the problem, store to the file exactly the number of characters entered by the user. Use std::string to make it easier.

Edit: The C++ way:

#include <iostream>
#include <string> 
#include <fstream>
using namespace std;
int main() {
    string x;
    cout << "enter something\n";
    getline(cin, x);
    ofstream o("d:/tester.txt");
    o << x;
}
Yakov Galka
  • 70,775
  • 16
  • 139
  • 220
  • I am unable to do this.Can you help please ? – Suhail Gupta Jun 30 '11 at 09:07
  • @ybungalobill: What? `getline` appends a NULL sentinel, and writes _up to_ 20 bytes. You are right in saying that he probably shouldn't be writing all 20 though. – Lightness Races in Orbit Jun 30 '11 at 10:05
  • @ybungalobill: In my opinion, your first paragraph is nonsense. There's no UB here. Using uninitialised pointers is UB, but reading garbage from an array of `char` (some of whose elements have not been initialised) is not. – Lightness Races in Orbit Jun 30 '11 at 10:19
  • @Suhail: What are you unable to do? And why? – Lightness Races in Orbit Jun 30 '11 at 10:22
  • @Tomalak: C++03 4.1 Lvalue-to-rvalue conversion: "If the object to which the lvalue refers is not an object of type T and is not an object of a type derived from T, *or if the object is uninitialized*, a program that necessitates this conversion has *undefined behavior*." – Yakov Galka Jun 30 '11 at 10:34
  • @ybungalobill: Where's the conversion? – Lightness Races in Orbit Jun 30 '11 at 12:47
  • @Tomalak: lvalue-to-rvalue conversion is the formalism of the C++ standard for defining 'reading' the value of an object. When the `put` parameter is initialized with the lvalue `x[i]` the conversion occurs. – Yakov Galka Jun 30 '11 at 13:41
  • @ybungalobill: I know what an `lvalue-to-rvalue` conversion _is_, but I'm still not convinced that it's occurring here. The `put` parameter has a name. Do you have a standard reference? – Lightness Races in Orbit Jun 30 '11 at 14:09
  • @Tomalak: It doesn't matter if `put`'s parameter has a name or not. See [the answer to your own question](http://stackoverflow.com/questions/6376580/what-standard-clause-mandates-this-lvalue-to-rvalue-conversion/6376743#6376743). Also "The process of initialization described in the remainder of 8.5 applies also to initializations specified by other syntactic contexts, such as the initialization of function parameters with argument expressions". – Yakov Galka Jun 30 '11 at 15:20
  • @Tomalak: and anyway, if you claim that the behavior here is defined, you are the one who have to provide the references where it is defined... – Yakov Galka Jun 30 '11 at 15:23
  • @ybungalobill: OK, I accept that an lvalue-to-rvalue conversion takes place here and thus that reading the end elements of the array _might_ be UB (if the user did not provide 20 of them). (No I don't. You posted an answer, containing an assertion. It's up to you to back up that assertion.) – Lightness Races in Orbit Jun 30 '11 at 15:24
  • @Tomalak: The only general way to prove the non-existence of x (the definition of some behavior) in a set Y (the standard) is to go through the whole set Y and check all the elements there. Posting here the whole standard is a copyright violation. – Yakov Galka Jun 30 '11 at 15:35
  • @ybungalobill: The standard explicitly mentions areas of undefined behaviour, criteria for conversions and rules of initialisation, as you demonstrated in your proof to me. – Lightness Races in Orbit Jun 30 '11 at 15:38
  • @tomalak, ybung is correct in that the lvalue to rvalue conversion happens here. The text of the spec says that the behavior is UB. But we can't interpret it literally here. We have to differentiate between memory reads and not-necessarily memory reads. Only the latter is intended to be undefined by the text of the lvalue to rvalue conversion. The former (memory reads) is allowed to read uninitialized char objects (by 3.9p2 ). There is a defect report about this (note the very last paragraph in that DR), see http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#240 ). – Johannes Schaub - litb Jul 02 '11 at 10:32