I have a Students class to store names, ages, gender, subjects, highestmark, lowestmark.
Basically, I have a reset() function which sets everything to null and it looks like this
char names[10];
char names[10];
char names[10];
int ages;
int highestMark;
int lowestMark;
void Students::reset()
{
strncpy(names, "NULL", sizeof(names));
names[9] = '\0';
ages = 0;
highestMark = 0;
lowestMark = 0;
strncpy(gender, "NULL", sizeof(gender);
gender[9] = '\0';
strncpy(subjects, "NULL", sizeof(subjects));
subjects[9] = '\0';
}
My constructor looks like this...
Students::Students()
{
reset();
}
Copy constructor looks like this...
Students::Students(const Students& student)
{
reset();
cout << highestMark << endl; // PRINTS 107894124
cout << lowestMark << endl; // PRINTS 541203654
cout << ages << endl; // PRINTS RANDOM VALUES
cout << subjects << endl;
cout << names << endl;
}
The highestMark and lowestMark are not returning 0 and instead returning random values such as 107894124 and 541203654
Why is it not returning 0 as expected?
strcpy(something, NULL) is undefined behavior, so anything can happen. Most likely you overwrite your data with some junk by calling strcpy like that. What you want is probably
strcpy(names, "");
But it would be much better if you just use std::string instead of raw character arrays.
Related
I am writing a program that takes some contact information from user and grows the array dynamically when it gets full. But when I am trying to run the program I get Write access violation popping up a line from "iosfwd standard header". I don't know where I went wrong. Please do help.
My code looks like this:
# include "pch.h"
# include <iostream>
# include <string>
using namespace std;
struct Contact {
string name;
string number;
string address;
string exit;
};
void userPrompt(Contact &contact) {
cout << "Name: ";
getline(cin, contact.name);
cout << "Phone number: ";
getline(cin, contact.number);
cout << "Address: ";
getline(cin, contact.address);
cout << "Exit? (y/n): ";
getline(cin, contact.exit);
}
void printContact(Contact &contact) {
cout << "Name: " << contact.name << endl;
cout << "Phone number: " << contact.number << endl;
cout << "Address: " << contact.address << "\n" << endl;
}
void growArray(int ¤tLength, Contact *contacts) {
int multiplyer = 2;
Contact *new_array = new Contact[currentLength * multiplyer];
for (int i = 0; i < currentLength; i++) {
new_array[i] = contacts[i];
}
delete[] contacts;
contacts = new_array;
currentLength *= multiplyer;
}
void showAllContacts(Contact *contacts, int length) {
for (int i = 0; i < length; i++) {
if (contacts[i].name.length() != 0) {
printContact(contacts[i]);
}
}
}
int main() {
// Prompt the user to fill in the address book.
// If the array gets full, make it bigger.
Contact *contacts = new Contact[1];
int currentLength = 1;
int i = 0;
while (true) {
userPrompt(contacts[i]);
if (contacts[i].exit == "y" or contacts[i].exit == "Y") {
break;
}
i++;
if (i == currentLength) {
growArray(currentLength, contacts);
}
}
// Show the address book
showAllContacts(contacts, currentLength);
}
But when I am running the code it throws exception like this:
enter image description here
"Write Access Violation"
I think the bug is in the growArray function. But I can't fugure out where did I screw up. Please do help.
In
growArray(currentLength, contacts);
a copy of the pointer contacts is modified inside the function; but outside, the pointer's value stays the same. After growArray returns, contacts points to deleted memory, hence UB, hence the crash.
==> Full program demonstration of the issue <==
There are basically two solutions: the bad one and the good one. The bad one is to change the signature of growArray to take a reference to the pointer:
void growArray(int ¤tLength, Contact *&contacts)
The good one is to stop this manually allocated memory non-sense and use a std::vector<Contact>!
This may be a dumb question but I'm getting pretty desperate at this point.
I am attempting to create an array of pointers:
struct vertex
{
std::string id;
std::string name;
int networkID;
std::vector<adjVertex> friends;
bool visited;
};
struct hobbylist
{
std::string hobby;
std::vector<vertex*> list;
};
hobbylist * hobbies[HASHMAP_SIZE];
int Graph::addUserToHobby(std::string hobby1, std::string id){
//cout << "Adding to hobby: " << hobby1 << " user: " << id << endl;
vertex *user = findVertex(id);
int collisions = 0;
// initial key is based on the first 2 characters of the hobby name
int key = (hobby1[0] + hobby1[1]) % HASHMAP_SIZE;
//cout << " initial hashmap key " << key << endl;
hobbylist *h = new hobbylist;
if(hobbies[key] == NULL){
h->hobby = hobby1;
h->list.push_back(user);
hobbies[key] = h;}
else if (hobbies[key]!=NULL){
hobbies[key]->list.push_back(user);
collisions++;}
return collisions;
}
I am getting a seg fault at the last line in the else statement in the addUserToHobby function when running the function the first time and I am confused why the function would go to the else statement when the array should be empty and therefore hobbies[key] should be null the first time the function is run? Upon further inspection the function will always enter the else statement, so the array values are never null?
Each location is the array is not set to null by default, it's just whatever trash was in there before you allocated it.
I want to implement a simple function that gets a string as a char pointer and modifies the string in a function. The requested function must be void then I have to modify the primary string passed into my function. I got an access violation error and googled it but nothing helped.
My sample code is here:
#include "iostream"
using namespace std;
void FindCommonStr(char*& Common,int &A)
{
int i=0;
while(1)
{
if(Common[i]=='\0')
break;
i++;
}
cout<<"Number of Elements = "<<i<<endl;
for (int j=0 ; j<i-1;j++)
Common[j]='y';
A=2;
}
void main()
{
int A=0;
char* Common = new char;
Common = "Hello World!";
cout<<"Common0 = "<< Common<<endl;
cout<<"A0 = "<< A<<endl;
FindCommonStr(Common,A);
cout<<"Common1 = "<< Common<<endl;
cout<<"A1 = "<< A<<endl;
}
Actually the problem occured in this part of FindCommonStr funtion:
for (int j=0 ; j<i-1;j++)
Common[j]='y';
If I comment this part everything works but I cannot change the string values. I also tested the pointer to pointer solution by defining the function as:
FindCommonStr(char **Common,...
It doesn't help though and I got the violation error again.
Is it even possible to do such a thing?
When you do this:
Common = "Hello World!";
you are making the pointer Common point at a literal C-style string (and incidentally leaking the original char that you allocated via new previously). It is not valid to try to modify such a literal, so when you pass this to FindCommonStr and try to modify it you get an access violation.
You should avoid using C-style strings and use proper C++ std::string instead - this will save a lot of problems and is much more robust, as well as being more appropriate for C++ programming.
Fixed version of your code:
#include <iostream>
#include <string>
using namespace std;
static void FindCommonStr(string &Common, int &A)
{
int i = 0;
while (1)
{
if (Common[i] == '\0')
break;
i++;
}
cout << "Number of Elements = " << i << endl;
for (int j = 0; j < i - 1; j++)
Common[j] = 'y';
A = 2;
}
int main()
{
int A = 0;
string Common = "Hello World!";
cout << "Common0 = " << Common << endl;
cout << "A0 = " << A << endl;
FindCommonStr(Common, A);
cout << "Common1 = " << Common<<endl;
cout << "A1 = " << A << endl;
return 0;
}
Alternatively if this is a homework assignment where you are required to use C strings for some unfathomable reason then a fixed version using only char * strings might look like this:
#include <iostream>
using namespace std;
static void FindCommonStr(char *Common, int &A)
{
int i = 0;
while (1)
{
if (Common[i] == '\0')
break;
i++;
}
cout << "Number of Elements = " << i << endl;
for (int j = 0; j < i - 1; j++)
Common[j] = 'y';
A = 2;
}
int main()
{
int A = 0;
char Common[] = "Hello World!";
cout << "Common0 = " << Common << endl;
cout << "A0 = " << A << endl;
FindCommonStr(Common, A);
cout << "Common1 = " << Common<<endl;
cout << "A1 = " << A << endl;
return 0;
}
This part is conceptually wrong:
char* Common = new char;
// 'Common' is set to point to a piece of allocated memory
// (typically located in the heap)
Common = "Hello World!";
// 'Common' is set to point to a constant string
// (typically located in the code-section or in the data-section)
You are assigning variable Common twice, so obviously, the first assignment has no meaning.
It's like writing:
int i = 5;
i = 6;
On top of that, you "lose" the address of the allocated memory block, so you will not be able to release it at a later point in the execution of your program.
You seem to mixup char[] and string
When you write
char* Common = new char;
you allocate space on the heap for one character which Common is pointing to.
Then you write
Common = "Hello World!";
which sets the pointer Common to point to the string "Hello World" in read-only memory. The heap you allocated previously is now leaked.
There are basically two approaches:
Either you work with arrays of characters, in that case you write something like
char* Common = new char[strlen("Hello World!")+1];
strcpy(Common, "Hello World!");
Now common still points to the heap and the string has been copied there. The extra +1 byte is to hold the ending \0 string terminator.
You need to free the memory Common points to once you are done.
delete Common;
The other approach is to use the string template
std::string Common;
this allows you to assign a string, it capsules all the work with the heap array above.
Common = "Hello World!";
and there is no need to delete anything afterwards since std::string will do that for you.
I wrote a simple function to perform in place reversal:
void in_place_reverse(char *str){
if(!str || !(*str)){
return;
}
char *str_end = str+strlen(str)-1;
int temp;
while(str < str_end){
temp = *str;
*(str++) = *str_end;
*(str_end--) = temp;
}
}
I'm just wondering why when I do something like this:
char str[] = "Reverse me!";
cout << "Original: " << str << endl;
in_place_reverse(str);
cout << "Reversed: " << str << endl;
str wasn't changed inside of the function. The reason I ask is because the line *(str++) is incrementing the pointer that points to str. So what I'm really asking is why something like this isn't necessary:
char *str_beg = str;
char *str_end = str+strlen(str)-1;
int temp;
while(str_beg < str_end){
temp = *str_beg;
*(str_beg++) = *str_end;
*(str_end--) = temp;
}
So that we're not actually changing the pointer that points to the first position of str.
You actually are doing this implicitely because 'str' is passed by value (read: 'as a copy in a temporary variable').
To clarify this without the (distracting) pointer: consider
void increment(int x) {
x++;
}
int i = 1;
cout << i << endl;
increment(i);
cout << i << endl;
This will print '1' twice. The x that is seen inside the increment routine has the same value like the passed i. But it is not the same variable i. In fact it is a copy of i. When we return from the routine, the copy is discarded. Further reading: This would be different if we'd pass x by reference, like so:
void increment(int &x) {
x++;
}
The declaration of the function void in_place_reverse(char *str) results in a copy of the pointer being created when the function is called, in a variable called str that is private and local to the in_place_reverse. You can modify this value all you like without affecting the original that exists in the scope of the calling function.
I realize the way I am approaching this is wrong, but I don't know why.
I am very new to C++/programming in general.
I want my program to do the following.
If I cin "setwanted joe" I want it to store joe into a char array. I have it so I can succesfully seperate and cout joe, but I am can't return the char array from the function.
Here's my example code.
char * GETNAME (char *searchinput, char*searchtext)
{
char returnname[64];
int starter=0;
for(;;)
{
if (*searchinput == *searchtext)
{
searchinput++;
searchtext++;
}
if (*searchinput == ' ')
{
searchinput++;
searchtext++;
}
if (*searchinput!='\0' && *searchinput!= *searchtext && *searchinput != ' ')
{
returnname[starter] = *searchinput;
starter++;
searchinput++;
searchtext++;
}
if (*searchinput=='\0')
{
returnname[starter]='\0';
cout << "Char Array to Return: " << returnname << endl;
return returnname;
}
}
}
Above is the function I made to try to return the name from the char array.
Here is the code I was using to call the function.
char Recv[256];
cin >> Recv;
char * wantedname = new char[64];
wantedname = GETNAME(Recv,"setwanted");
cout << "Returned Name: " << wantedname << endl;
Thanks for reading/your patience I know this is messy.
Use std::array, std::vector or std::string (in case of array of characters) to easily return an array of items. You're code invokes undefined behavior due to returning a pointer to a local temporary object. I prefer this
std::string GETNAME(const std::string &searchinput,const std::string &searchtext)
{
std::string returnname;
...
return returnname;
}