A good file type to use?

Started by
21 comments, last by Bolthame 16 years, 9 months ago
Well, a file is just a collection of bytes. It's not much different than if you were to declare a byte array in your program, except that this one is stored on your disc. "Text files" typically encode ASCII characters so they only use seven of the eight bits in each byte. What makes the difference between file formats is not the extension but the contents. Typically some file, say an image or a movie, contains the file format type encoded in the first couple of bytes in the file, that's how programs differentiate them.

DOS programs don't typically have a clipboard, which is a feature offered by the windowing system or graphical shell. Special libraries such as ncurses might offer a clipboard however. If you need one, you'll have to write it yourself, which is as simple as declaring an array to hold bytes or chars or something similar, but implementing text editing in your program to send data to and from that buffer might be more difficult.
Advertisement
There is no such thing as a file the user cannot edit. There is not even such a thing as a file the user cannot edit meaningfully. There is, however, such a thing as a file the user cannot *easily figure out how to* edit meaningfully. It's usually not worth the effort to bother, though.

Quote:Original post by Bolthame
1: How can I get cin (or something that works the same) to work with spaces?


That depends on what you mean by "work". I'll try to read your mind, though: The operator>> on an input stream (which is to say, a file stream that is open for input, or std::cin, or a stringstream that allows reading) reads one "word" (separated by whitespace) into a target std::string variable (or into memory pointed to by a char*, but you really shouldn't be doing this). To read a whole "line" (delimited by a return character, by default; but you can specify any character to act as the delimiter) into the variable, use the free function std::getline(stream instance, target string).

Quote:2: How can I have a program I/O to the clipboard?


I assume you are talking about Windows. This is OS-specific (There are a lot of computers in the world still whose users would have *no idea* what you meant by "clipboard"), so you'll need to pull in Windows headers and do Windows-specific development. I don't know anything about this task in particular, but the best starting point to find out is MSDN.

Here, I digged up some old library of mine allowing to read/write to the clipboard. Some stuff is library-specific but you should be able to figure it out.

bool WriteTextToClipboard(const String & text){    if(!OpenClipboard(NULL)) return false;	HGLOBAL bufferhandle;	EmptyClipboard();	bufferhandle = GlobalAlloc(GMEM_MOVEABLE, text.length() + 1); // +1 for null-terminator	if(bufferhandle)	{		char * buffer = (LPTSTR)GlobalLock(bufferhandle);		memcpy(buffer, text.strz(), text.length()+1); // +1 for null-terminator		GlobalUnlock(bufferhandle);		SetClipboardData(CF_TEXT, bufferhandle);	}	CloseClipboard();	return true;}bool LoadTextFromClipboard(String & text){	if(!OpenClipboard(NULL)) return false;	text = (const FEchar*)GetClipboardData(CF_TEXT);	CloseClipboard();	return true;}


Now if you're really beginning, this might be a bit confusing, you might want to get to it later.
Yeah, haha, that's way beyond me. Ah well, I'll do it later on when I'm working with windows programs instead of DOS :)

And thanks Zahlman for telling me about getline(), but what did you mean by string instance? (Sorry for asking such noobish questions, but I'm really very much a beginner at this :))
_________________He who laughs when things go wrong has thought of someone to blame it on.
Quote:Original post by Bolthame
Yeah, haha, that's way beyond me. Ah well, I'll do it later on when I'm working with windows programs instead of DOS :)


Nitpicking point, but that's really DOS. DOS is an operating system. Windows XP (what I'm guessing you're using) is an operating system. Older versions of Windows ran on Top of DOS, but the thing you are using, the console, is just the command line interpretation of the windows XP operating system. The same functionality exists, just in different forms.

Okay, that aside-- stream instances. std::cin is an instance of a stream. std::fstream is a stream type that can be used to create an instance of a stream to read or write from files. std::stringstream is a stream type that can be used to create generic streams that aren't tied to a specific device (console, file, whatever). What do these things have in common? They inherit from a common base class. Because they all inherit from the same base class you can write the a function using only that base class and then you can pass any derived object to said base class. This page describes the inheritance heirarchy of all of the streams. std::getline probably expects an istream or any of its derivitives.

Hope that helps.

C++: A Dialog | C++0x Features: Part1 (lambdas, auto, static_assert) , Part 2 (rvalue references) , Part 3 (decltype) | Write Games | Fix Your Timestep!

Ahh, I think I get it now.

Also, one more thing:

Is there any way to take a letter from a word and change it?

What I need in a nut shell is a way to convert letters into numbers.

Thanks again for your help :)
_________________He who laughs when things go wrong has thought of someone to blame it on.
Quote:Original post by Bolthame
Ahh, I think I get it now.

Also, one more thing:

Is there any way to take a letter from a word and change it?


The std::string class represents a mutable string, so yes. You can index into the string just as if it were an array of characters, and assign a different character at the appropriate position.

Quote:What I need in a nut shell is a way to convert letters into numbers.


This is quite ambiguous. Please give some examples.
Well what I'm doing is a challenge to create a program that works like the enigma code (you can't decode it unless you have the code the person who encoded it has). So what I have so far is, it takes a letter, makes it into a number (a = 1, b = 2, c = 3, etc), generates a random number (this is also the code used to decode the message), and then multiplies, adds, divides and subtracts by it, gives you the code and saves the encoded message, which will look like a load of random numbers. As part of the challenge, the message must be one letter per line, for some reason. So far I have this code:

#include <iostream>#include <fstream>#include <string>#include <windows.h>#include <cstdlib>#include <time.h>using namespace std;int main(){    string letter;    int letternumber;srand(time(NULL));    int code = rand(); //This generates the random number which the letters will be encoded by    ifstream fin;    fin.open("Encode.txt"); //This loads the file in program input, so it inputs to the program, as this is the file where    while(! fin.eof() )     //the program gets the letters to encode.    {            getline (fin, letter);            if(letter == "a" || letter == "A")            {                      fin.close();                      letternumber = (1 * code) + code;                      ofstream fout;                      fout.open("Encoded_Message.txt");                      fout << letternumber << "\n";                      fout.close();                      fin.open("Encode.txt");            }            if(letter == "b" || letter == "B")            {                      fin.close();                      letternumber = (2 * code) + code;                      ofstream fout;                      fout.open("Encoded_Message.txt");                      fout << letternumber << "\n";                      fout.close();                      fin.open("Encode.txt");            }            if(letter == "c" || letter == "C")            {                      fin.close();                      letternumber = (3 * code) + code;                      ofstream fout;                      fout.open("Encoded_Message.txt");                      fout << letternumber << "\n";                      fout.close();                      fin.open("Encode.txt");            }            if(letter == "d" || letter == "D")            {                      fin.close();                      letternumber = (4 * code) + code;                      ofstream fout;                      fout.open("Encoded_Message.txt");                      fout << letternumber << "\n";                      fout.close();                      fin.open("Encode.txt");            }            if(letter == "e" || letter == "E")            {                      fin.close();                      letternumber = (5 * code) + code;                      ofstream fout;                      fout.open("Encoded_Message.txt");                      fout << letternumber << "\n";                      fout.close();                      fin.open("Encode.txt");            }    }    fin.close();    system("CLS");    cout << "Encoding complete. Your decode code is: " << code << ".\n";    cout << "Please remember this code as it is the only way to decode your message.\n";    system("Pause");    return 0;}


But it only encodes the first line, and then gets stuck, what's wrong with it?
_________________He who laughs when things go wrong has thought of someone to blame it on.
You open and close the file every time? So the only thing you see is the last thing written to the file, not the first (std::ofstream::open truncates the file unless you tell it otherwise).

Also, note that it is idiomatic to use the std::getline as the loop condition:
while( std::getline(fin,letter) ) {   // process input}


It is also idiomatic to open a file stream at the same time as declaring it:
ifstream fin("Encode.txt");


In this example open both the read and write files just before the loop, and read from one and write to the other. Don't bother with opening and closing the file every loop, its too complicated. Anyway I don't see a reason to open and close the file continuously either.

As a hint, instead of writing the same code over and over to handle each different letter, recall that each ascii letter is given a number. A symbol representing this number in your C++ source code is 'a', 'b'...'z'. These are character literals and can be treated the same way you would treat a number.

Note that 'a'-'a' = 0. This may not look helpful, but 'b'-'a' = 1, and 'c' - 'a' = 2, and so on. This is almost what we need to get the sequence (a = 1, b = 2 ,c = 3).

Using the function "tolower" (I think it is in <ctype>) we can find the lower-case value of any character. From there you may be able to piece together an algorithm to get the numeric value of an arbitrary letter, in upper or lower case.

I will leave it to you to see if you can [smile].

[edit: also, you can use a std::string like an array. So to get the character value of the first letter in a string named str use str[0] [/edit]
Quote:Original post by Bolthame
Well what I'm doing is a challenge to create a program that works like the enigma code (you can't decode it unless you have the code the person who encoded it has).


A challenge from where?

Quote:So what I have so far is, it takes a letter, makes it into a number (a = 1, b = 2, c = 3, etc), generates a random number (this is also the code used to decode the message), and then multiplies, adds, divides and subtracts by it, gives you the code and saves the encoded message, which will look like a load of random numbers.


::facepalm:: Please don't try to make up the algorithm for scrambling things. It's very easy to create something that *weakens* the encryption when you think you're strengthening it. Anyway, no matter what your algorithm is, if you just take a *single* random number and consider the letters of the message *separately*, you get the same effective result: a simple substitution cipher.

Quote:As part of the challenge, the message must be one letter per line, for some reason. So far I have this code:


1) Don't compare the lines to various one-character string literals. Instead, check that the line is one character long, and then grab the first (and only) character. You don't need to compare the character to character literals, because characters are numbers: you can check them arithmetically.

(Also, note that '(x * code) + code' is equivalent to '(x + 1) * code', for all X; again, please don't try to make up the algorithms. Just doing the multiplication would give you all the benefit you can get out of this approach, and actually it's quite poor: not only is it subject to cryptographic analysis like any simple substitution cipher, but the "random" numbers in the output will be quite strongly patterned - once I know one letter value, I can guess the others easily.)

2) You absolutely do not need windows.h for this. Cut it out. Also, time.h is now ctime in C++.

3) It is very rare that you call .close() on any stream object. Here, it's the cause of your problem: you are closing and reopening the input file immediately, the first time through the loop, which resets the file reading to the beginning. Stream objects automatically .close() themselves when they go out of scope, so you only use it explicitly in very special circumstances. Similarly, you want to open the output file at the beginning of the loop, and keep it open until you've finished processing.

4) As noted, don't check for .eof() to loop here. Instead, use the reading expression as the loop conditional, as shown.

5) Normally, use the constructor of the stream to open it.

6) Don't artificially pause your programs at the end. (Also, clearing the screen is kind of overkill here.) In general, system() calls are a bad idea in C++, because if you really wanted/needed to call other programs to do your work, you should be writing a shell script instead.

#include <iostream>#include <fstream>#include <string>#include <cstdlib>#include <ctime>using namespace std;int main() {  srand(time(NULL));  int code = rand();  ifstream fin("Encode.txt");  ofstream fout("Encoded_Message.txt");  string line;  while (!getline(fin, line) {    if (line.size() != 1) { continue; } // not a single-letter line.    char letter = line[0];    if (letter >= 'a' && letter <= 'z') {      fout << ((letter - 'a' + 1) * code) << "\n";    } else if (letter >= 'A' && letter <= 'Z') {      fout << ((letter - 'A' + 1) * code) << "\n";    }  }  cout << "Encoding complete. Your decode code is: " << code << ".\n";  cout << "Please remember this code as it is the only way to decode your message.\n";}

This topic is closed to new replies.

Advertisement