weird error

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

1
2
3
4
#include "functions.h"
#include <iostream>                                                                                     

using namespace std;


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.

1
2
3
4
#include <iostream>                                                                                     
#include "functions.h"

using namespace std;


Is it best practice to put user headers first? and if so why does mine cause an error when I do this?

1
2
3
4
5
6
7
8
9
using namespace std;                                                                                    

#ifndef FUNCTIONS_H_INCLUDED                                                                            
#define FUNCTIONS_H_INCLUDED                                                                            

void testchar(int testcount, char testch, int testlength);                                              
string testchar2(int testcount2, char testch2, int testlength2);                                        

#endif // FUNCTIONS_H_INCLUDED 


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.

Thanks

Brian
Last edited on
main.cpp - forgive me is this is not very elegant I'm only about 10-12hrs in c/c++

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>                                                                                     // This includes the iostream header file <> are compiler header files
#include "functions.h"                                                                                  // This is a user created header

using namespace 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;
}

functions.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <iostream>                                                                                     // We are using commands from the iostream cout etc so we must include it

using namespace 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;
    }
    else if (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;
    }
    else if (testcount == 3 && testlength >= 3)                                                         // Same as above but for 3 letter words
    {
        cout << testch << " was the 3rd character" << endl;
    }
    else if (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";
    }
    else if (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";
    }
    else if (testcount2 == 3 && testlength2 >= 3)
    {
        testmessage += testch2;
        testmessage += " was the 3rd character";
    }
    else if (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
}
Last edited on
functions.h

1
2
3
4
5
6
7
8
9
10
using namespace 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
Last edited on
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.

Thanks
Hello BrianD,

Working with what you posted I came up with this:

Main.cpp
1
2
3
4
5
6
7
8
#include <iostream>  // This includes the iostream header file <> are compiler header files
#include <string>  // <--- Added.

using namespace 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.

using namespace 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 


It is best not to put the line using namespace std; in a header file. see: http://www.lonecpluspluscoder.com/2012/09/22/i-dont-want-to-see-another-using-namespace-xxx-in-a-header-file-ever-again/

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.

Andy
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
Last edited on
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.

Thank You

Brian
@Handy Andy wrote:
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 using namespace 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.
Herb Sutter wrote in https://herbsutter.com/2013/08/19/gotw-7a-solution-minimizing-compile-time-dependencies-part-1/
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.

(shows many cases when you don't need includes)

and about namespaces in http://www.gotw.ca/publications/migrating_to_namespaces.htm


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
Last edited on
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>

using namespace std;  // Specify we are using the std namesapce 
Last edited on
...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.
Last edited on
Topic archived. No new replies allowed.