Access violation

Im running into an issue with the compiler, trying to understand what is wrong here.

//header
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#ifndef SICT_PASSENGER_H
#define SICT_PASSENGER_H

namespace sict
{
	class Passenger
	{
		char name[32];
		char destination[32];
	public:
		Passenger();
		Passenger(char* name, char* destination);
		bool isEmpty() const;
		void display() const;
	};
}

#endif //SICT_PASSENGER_H 


//implementation file
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
#include "Passenger.h"
#include <cstring>
#include <iostream>

using namespace std;

namespace sict
{
	Passenger::Passenger()
	{
		name[0] = '\0';
		destination[0] = '\0';
	}
	Passenger::Passenger(char* nameString, char* destinationString)
	{
		if ('\0' != name && '\0' != destination)
		{
			for (int i = 0; i < strlen(nameString); i++)
			{
				name[i] = nameString[i];
			}
			for (int i = 0; i < strlen(destinationString); i++)
			{
				destination[i] = destinationString[i];
			}
		}
	}
	bool Passenger::isEmpty() const
	{
		if ('\0' == name[0] && '\0' == destination)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	void Passenger::display() const
	{
		if (!isEmpty())
		{
			for (int i = 0; i < strlen(name); i++)
			{
				cout << name[i];
			}
			cout << " - ";
			for (int i = 0; i < strlen(destination); i++)
			{
				cout << destination[i] << endl;
			}
		}
		else
		{
			cout << "No Passenger!" << endl;
		}
	}
}


//main
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
#include <iostream>
#include "Passenger.h"

using namespace std;
using namespace sict;

int main()
{
	Passenger travellers[] = {
		Passenger(nullptr, "Toronto"),
		Passenger("", "Toronto"),
		Passenger("John Smith", nullptr),
		Passenger("John Smith", ""),
		Passenger("John Smith", "Toronto"), // valid
		Passenger(nullptr, nullptr),
		Passenger()
	};
	cout << "----------------------------------------" << endl;
	cout << "Testing the validation logic" << endl;
	cout << "(only passenger 5 should be valid)" << endl;
	cout << "----------------------------------------" << endl;
	for (int i = 0; i < 7; ++i)
	{
		cout << "Passenger " << i + 1 << ": " << (travellers[i].isEmpty() ? "not valid" : "valid") << endl;
	}
	cout << "----------------------------------------" << endl << endl;

	Passenger vanessa("Vanessa", "Paris"),
		      mike("Mike", "Tokyo"),
		      alice("Alice", "Paris");

	cout << "----------------------------------------" << endl;
	cout << "Testing the display function" << endl;
	cout << "----------------------------------------" << endl;
	vanessa.display();
	mike.display();
	alice.display();
	travellers[0].display();
	cout << "----------------------------------------" << endl << endl;

	return 0;
}
You would see that if the program is currently running. Close all windows.
cout groks strings that end in zero. You can print them with cout << char_array_variable<< without looping 1 char at a time.

eg cout << destination << endl is the same as a loop over destination[i].
'\0' is fancy for 0 . if you prefer the explicit form, that is fine.


I don't see anything right off except this:

Passenger(nullptr, nullptr),

and I have to wonder if you are crashing trying to access this or one of the other partly null entries. I suspect the issue is that you have confused a null pointer and an empty string.
char *cp = nullptr;
if(cp[0] == 0) //fail: cp CANNOT be accessed at all! It is NOT the empty string.

char cp[10] = {0};
if(cp[0] == 0) //OK. Cp is the empty string.

specifically your function isempty tries to access unallocated pointers, if i followed your code correctly (just looking at it, I didnt compile and all that yet). I am not 100% sure, name and dest are not pointers so this may be failure to follow the code on my part.



It may also be your constructor. The constructor checks both being null and if either are ... it does nothing, and that leaves destination and name uninitialized, this could be the source of the crash as well.

I think you need to add an else to the char* version of the ctor that sets them to empty string if not valid inputs.

Last edited on
Why are you trying to copy each individual character from one string to the next instead of just using strcpy() instead? Edit: If you stay with your current approach don't forget to properly terminate those strings.

And because you're trying to pass nullptr as some of the parameters you need to be careful not to try to use those parameters when they are set to nullptrs.

You also have quite a few warning: deprecated conversion from string constant to ‘char*’ warnings in main(), caused by the following:
1
2
3
4
5
6
7
8
9
	Passenger travellers[] = {
		Passenger(nullptr, "Toronto"),
		Passenger("", "Toronto"),
		Passenger("John Smith", nullptr),
		Passenger("John Smith", ""),
		Passenger("John Smith", "Toronto"), // valid
		Passenger(nullptr, nullptr),
		Passenger()
	};

You should consider const qualifying the parameters in that constructor to solve this problem.



Last edited on
jlb,

When I changed it to Passenger::Passenger(const char* nameString, const char* destinationString), it throws and error,
1
2
unresolved external symbol "public: __thiscall sict::Passenger::Passenger(char *,char *)" 
(??0Passenger@sict@@QAE@PAD0@Z) referenced in function _main


But when I get rid of const char*, it compiles and works just fine. Im trying to figure out a way around this, can you please advise?

Here's my updated code: https://pastebin.com/8ePMyjPu
Last edited on
jonnin,

yes, it was my constructor.

I've changed the implementation to,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
	Passenger::Passenger(const char* nameString, const char* destinationString)
	{
		if ("" == nameString || "" == destinationString || '\0' == nameString || '\0' == destinationString)
		{
			setEmpty();
		}
		else
		{
			for (int i = 0; i < strlen(name); i++)
			{
				name[i] = nameString[i];
			}
			for (int i = 0; i < strlen(destination); i++)
			{
				destination[i] = destinationString[i];
			}
		}
	}
Last edited on
Line 3: You can't compare C-strings like that. e.g. nameString and "" are pointers. You're comparing the pointers. Not the strings. The == operator operator only works with C++ strings.

When I changed it to Passenger::Passenger(const char* nameString, const char* destinationString), it throws and error,

Did you change both the definition and the implementation? They must both match.

AbstractionAnon,

How would you recommend I fix this (Im getting the below warnings)? I have no idea how to go about this, we werent taught of this error in my class (yet, I guess).

jlb,

I did, now it all compiles and runs, but Im still getting the errors.
warning: deprecated conversion from string constant to ‘char*’
and
warning: comparison with string literal results in unspecified behaviour

And when I change the definition and implementation to,
Passenger::Passenger(const char* nameString, const char* destinationString);
I get the error,
unresolved external symbol "public: __this call sict::Passemger::Passenger(char *, char *)" (??0Passenger@sict@@QAE@PAD0@Z) referenced in function _main
Last edited on
I have managed to fix the first and last error by writing

1
2
3
4
else
{
    Passenger::setEmpty();
}


in the constructor.

But I still have two (EDIT: only one now) errors:
 
warning: comparison with string literal results in unspecified behaviour

and
1
2
//EDIT: I fixed this by changing 'int i' to 'size_t i'
warning: comparison between signed and unsigned integer expressions

in my implementation file,

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
62
63
64
65
66
67
#include "Passenger.h"
#include <cstring>
#include <iostream>

using namespace std;

namespace sict
{
	Passenger::Passenger()
	{
		Passenger::setEmpty();
	}
	Passenger::Passenger(const char* nameString, const char* destinationString)
	{
		if ("" == nameString || "" == destinationString || '\0' == nameString || '\0' == destinationString)
		{
			setEmpty();
		}
		else
		{
			for (int i = 0; i < strlen(name); i++)
			{
				name[i] = nameString[i];
			}
			for (int i = 0; i < strlen(destination); i++)
			{
				destination[i] = destinationString[i];
			}
		}
	}
	void Passenger::setEmpty()
	{
		name[0] = '\0';
		destination[0] = '\0';
	}
	bool Passenger::isEmpty() const
	{
		if ('\0' == name[0] && '\0' == destination[0])
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	void Passenger::display() const
	{
		if (!isEmpty())
		{
			for (int i = 0; i < strlen(name); i++)
			{
				cout << name[i];
			}
			cout << " - ";
			for (int i = 0; i < strlen(destination); i++)
			{
				cout << destination[i];
			}
			cout << endl;
		}
		else
		{
			cout << "No Passenger!" << endl;
		}
	}
}

Last edited on
What’s bad in std::string?

Passenger.h:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#ifndef SICT_PASSENGER_H
#define SICT_PASSENGER_H
 
namespace sict 
{
    class Passenger
    {
        char name[32];
        char destination[32];
    public:
        Passenger();
        Passenger(const char* nameString, const char* destinationString);
        bool isEmpty() const;
        void display() const;
        void setEmpty();
    };
}
 
#endif //SICT_PASSENGER_H 


Passenger.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
#include <cstring>
#include <iostream>
#include "Passenger.h"

namespace sict
{
    Passenger::Passenger() { Passenger::setEmpty(); }

    Passenger::Passenger(const char* nameString, const char* destinationString)
    {
        if (nullptr == nameString || nullptr == destinationString 
            || '\0' == nameString[0] || '\0' == destinationString[0])
        {
            setEmpty();
        }
        else
        {
            std::strcpy(name, nameString);
            std::strcpy(destination, destinationString);
        }
    }

    void Passenger::setEmpty()
    {
        name[0] = '\0';
        destination[0] = '\0';
    }

    // Returns true if and only if BOTH name and destination are empty.
    // Otherwise returns false.
    bool Passenger::isEmpty() const
    {
        if ('\0' == name[0] && '\0' == destination[0])
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    void Passenger::display() const
    {
        if (!isEmpty()) // or name or destination could be empty
        {
            std::cout << name << " - " << destination << '\n';
        }
        else
        {
            std::cout << "No Passenger!\n";
        }
    }
}


main.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
#include <cstring>
#include <iostream>
#include "Passenger.h"

using namespace sict;

int main()
{
    Passenger travellers[] = { {nullptr, "Toronto"},
                               {"", "Toronto"},
                               {"John Smith", nullptr},
                               {"John Smith", ""},
                               {"John Smith", "Toronto"}, // valid
                               {nullptr, nullptr},
                               {} };

    std::cout << "----------------------------------------\n"
                 "Testing the validation logic\n"
                 "(only passenger 5 should be valid)\n"
                 "----------------------------------------\n";
    for (int i = 0; i < 7; ++i)
    {
        std::cout << "Passenger " << i + 1 << ": " 
                  << (travellers[i].isEmpty() ? "not valid\n" : "valid\n");
    }
    std::cout << "----------------------------------------\n\n";
 
    Passenger vanessa("Vanessa", "Paris"),
              mike("Mike", "Tokyo"),
              alice("Alice", "Paris");
    std::cout << "----------------------------------------\n"
                 "Testing the display function\n"
                 "----------------------------------------\n";
    vanessa.display();
    mike.display();
    alice.display();
    travellers[0].display();
    std::cout << "----------------------------------------\n\n";
 
    return 0;
}

"" == nameString

Here, you are comparing a pointer to a pointer. You are NOT, repeat NOT, checking if the string represented by nameString is blank.

A pointer is a memory address. "" is interpreted as a char-pointer, nameString is a different char-pointer. You are comparing two memory addresses to see if they're the same memory address. I suspect this is not what you intended.

The short answer is don't use char*. This isn't C. If you want a string, use a string.

The longer answer is spend time learning about pointers and char arrays and char pointers, and then don't use them; if you want a string, use a string.
Topic archived. No new replies allowed.