Hi I an very new to this and have a question I am following a book to learn C++ and it tells me that I should put user headers first in my main program then 3rd party libs then <> headers and example of which is below
however if I do this I get an error in my header file "error: 'string' does not name a type; did you mean 'stdin'?". This seems to be fixed by putting the includes the other way round.
The void line works and the string line is the one that causes the error. As I said this is fixed by putting the includes the other way round. I would just like to know why it does it more than anything.
Also if I run this code in codeblocks it bails the first time exiting the console and then if I do nothing and run it again it works without any issues.If I run it 10 times it works every time but if I leave it for a bit and come back to it it fails first time through again. Basically I just wrote a program to read in a word then a character and then I wrote two functions to find the first occurrence of that character in the word. The functions are almost identical apart from one outputs to the console and one returns a string that I then output to the console (I was just experimenting with returning things in functions) anyway I got it all to work so I then decided to move my functions to a separate cpp file with a header (because that was the next chapter in my book) and it now misbehaves. It never bailed when the code was in one file.
#include <iostream> // This includes the iostream header file <> are compiler header files
#include "functions.h" // This is a user created header
usingnamespace std;
int main()
{
string myword, message; // define two string variables
char mychar; // define a character variable
int counter = 0, wordlength = 0; // the counter starts from 0 because we are checking for the position of a character in a string and that always starts as character 0 not 1
cout << "Enter a word please" << endl; // output "Enter a word please" to the console
cin >> myword; // read in a word from the console into variable myword
wordlength = myword.length(); // set the variable wordlength to the length of the word you read into myword
cout << "Your word is " << myword << endl; // output the word to the console
cout << "Your word is " << wordlength << " characters long" << endl; // output the length to the console
cout << endl << "Please enter a character to search for" << endl; // output prompt to console
cin >> mychar; // read in a single character into mychar
cout << "\n" << "The character you pressed was " << mychar << endl; // create a new line \n then print to console the message and mychar variable
while (myword[counter] != mychar && counter < wordlength) // this tests the characters first position in word myword to see if its the character were looking for. If not it repeats for each character up until we have searched all the characters
{ // This function only finds the first occurrence of a character, you could change this to use an array to store every occurrence
// cout << "Count = " << counter + 1 << " Read character " << myword[counter] << " Input character = " << mychar << " Word length = " << wordlength << endl; debugging line
counter++; // increment the counter variable
}
counter++; // correction for the counter not starting at 1
testchar(counter, mychar, wordlength); // Call function testchar using the parameters listed
message = testchar2(counter, mychar, wordlength); // Call function testchar2 using the parameters listed and return the answer as a string
cout << endl; // output a blank line to the console
cout << message << endl; // output the sting message to the console
return 0;
}
#include <iostream> // We are using commands from the iostream cout etc so we must include it
usingnamespace std; // Specify we are using the std namesapce
void testchar(int testcount, char testch, int testlength) // This is a reusable function that takes parameters and tests them
{
if (testcount == 1)
{
cout << testch << " was the 1st character" << endl;
}
elseif (testcount == 2 && testlength >= 2) // test to see if our char was the 2nd and our word length is no less than 2 characters this prevents words < 2 chars from an error
{
cout << testch << " was the 2nd character" << endl;
}
elseif (testcount == 3 && testlength >= 3) // Same as above but for 3 letter words
{
cout << testch << " was the 3rd character" << endl;
}
elseif (testcount >= 4 && testcount <= testlength)
{
cout << testch << " was the " << testcount << "th character" << endl;
}
else
{
cout << "Character " << testch << " not found" << endl;
}
}
string testchar2(int testcount2, char testch2, int testlength2) // This is the same function as above it just returns a string with the message instead as opposed to cout
{
string testmessage;
if (testcount2 == 1)
{
testmessage += testch2;
testmessage += " was the 1st character";
}
elseif (testcount2 == 2 && testlength2 >= 2) // test to see if our char was the 2nd and our word length is no less than 2 characters this prevents words < 2 chars from an error
{
testmessage += testch2;
testmessage += " was the 2nd character";
}
elseif (testcount2 == 3 && testlength2 >= 3)
{
testmessage += testch2;
testmessage += " was the 3rd character";
}
elseif (testcount2 >= 4 && testcount2 <= testlength2)
{
testmessage += testch2; // adding a character and strings at the same time to a string causes an error so I have done the char first
testmessage += " was the " + to_string(testcount2) + "th character"; // and the strings second (converting the int testcount2 to a string at the same time)
}
else
{
// You can add strings and characters to a string at the same time so you do them one at a time you could convert the char to as string using string(1,testch2)
testmessage = "Character ";
testmessage += testch2;
testmessage += " not found";
}
return testmessage; // return the string test message back to the code that called this function
}
usingnamespace std; // Specify we are using the std namesapce
#ifndef FUNCTIONS_H_INCLUDED // This is a header (or include) guard it checks to see if this header has already been defined, this prevents duplication as this will prevent compiling
#define FUNCTIONS_H_INCLUDED // If not it defines the header
void testchar(int testcount, char testch, int testlength); // This is function prototype - This defines a later function
string testchar2(int testcount2, char testch2, int testlength2); // This is the same function prototype as above it just returns a string with the message instead as opposed to cout
#endif // FUNCTIONS_H_INCLUDED
As I said this weirdness only happens when I run this as separate files if I move the functions back to the main.cpp the program doesn't bail first run and I don't get the weird error.
#include <iostream> // This includes the iostream header file <> are compiler header files
#include <string> // <--- Added.
usingnamespace std;
#include "functions.hpp" // This is a user created header
int main()
If you need your comments that s fine, but you really do not need them.
Functions.hpp
1 2 3 4 5 6 7 8
#ifndef FUNCTIONS_H_INCLUDED // This is a header (or include) guard it checks to see if this header has already been defined, this prevents duplication as this will prevent compiling
#define FUNCTIONS_H_INCLUDED // If not it defines the header
void testchar(int testcount, char testch, int testlength); // This is function prototype - This defines a later function
string testchar2(int testcount2, char testch2, int testlength2); // This is the same function prototype as above it just returns a string with the message instead as opposed to cout
#endif // FUNCTIONS_H_INCLUDED
Functions.cpp
1 2 3 4 5 6 7 8
#include <iostream> // We are using commands from the iostream cout etc so we must include it
#include <string> // <--- Added.
usingnamespace std; // Specify we are using the std namesapce
#include "Functions.hpp"
void testchar(int testcount, char testch, int testlength) // This is a reusable function that takes parameters and tests them
When I compiled this with MSVS 2017 I received no errors.
Notice that in the ".cpp" files the include statement came after the using statement. Since you feel this s some great time saver, just wait awhile.
Another option is to put #include <string> in the header file. And I would use: using std::string; to only use what you need. This using statement would also work in the ".cpp"files.
Functions.hpp should not really be reliant upon a required #include (string in this case) already having been included. There is/should be no problem with having the same header file included more than once. Also, as Andy says above, don't put using in a header file. At some point this practice will give your problems - so don't get into the habit.
In terms of ordering, we always use:
any required #define statements
std:: headers (eg iostream)
c headers (eg conio.h)
windows headers (eg windows.h)
3rd party headers
user headers
Thank you very much for the pointers, I know I've overdone it with the comments at the moment but it's useful for me right now to help me remember what stuff is doing.
Another option is to put #include <string> in the header file.
@seeplus wrote:
Functions.hpp should not really be reliant upon a required #include (string in this case) already having been included.
To be a little bit more clear--Anything required by the header file should be included by the header file. Thus, since Functions.hpp uses string, then <string> should be included in Functions.hpp.
@Handy Andy also wrote
And I would use: using std::string; to only use what you need.
While this is better than adding usingnamespace std; to a header file, I would not recommend it. It's fine in a .cpp file, but things get a little bit shakier in a header file.
If you end up including this header file in multiple source files, and one of those source file defines another class named "string", there could be name collisions and confusion on the part of the compiler that may be very difficult to identify.
While it won't cause problems in your beginner programs, it is sitll a habit best not to start.
Guideline: Never #include unnecessary header files. Guideline: Prefer to #include <iosfwd> when a forward declaration of a stream will suffice. Guideline: Never #include a header when a forward declaration will suffice.
Alas, there is no forward declaration for std::string.
The fact that <iostream> includes definition of std::string is unfortunate:
* Explicitly including just one library header pulls in who-knows-how-many headers. Oh well, the modules are coming.
* All library implementations do not behave the same; trusting on implicit includes can hamper portability.
* Explicit include is a statement about the code that follows
I know I've overdone it with the comments at the moment
You should see my evolving code as I bash around things and ideas, comments everywhere. Later when the code is 'finished' do I pare back many of the comments.
Too many comments is better than not enough. Write some code and put it aside for a couple of days/weeks/months/years. What was clear to you when you first wrote it is not so understandable now.
About the only thing I would recommend is not so much whitespace with the comments. The comments should be visible near the bits of code they are commenting on. :)
1 2 3 4
// We are using commands from the iostream cout etc so we must include it
#include <iostream>
usingnamespace std; // Specify we are using the std namesapce
...and make sure the comments reflect the code. If the code changes, the comment should reflect this. There's nothing worse than looking at some code that seems to do one thing with the comments indicating it does something different.....
Your use of comments as a beginner is fine, since it's just helping you study/remember things on a personal level. Just note that comments that just repeat the code itself, like "specify we are using the std namespace" are not helpful/necessary for public-facing code. It's more important that a comment explain why something is happening, in most cases.