Strange C++ output with boolean pointer - c++

I have the following code:
#include <iostream>
using namespace std;
int main() {
int n = 2;
string s = "AB";
bool* xd = nullptr;
for (int i = 0; i < n; i += 100) {
if (xd == nullptr) {
bool tmp = false;
xd = &tmp;
}
cout << "wtf: " << " " << (*xd) << " " << endl;
}
}
When I run this on my own mac with g++ -std=c++17, I get a random integer every time (which is odd since *xd should be a bool). Weirdly enough, this doesn't happen on online IDEs like csacademy and onlinegdb.

if (xd == nullptr) {
bool tmp = false;
xd = &tmp;
}
tmp is an automatic variable. It is destroyed automatically at the end of the scope where the variable is declared. In this case, the lifetime of the object ends when the if-statement ends. At that point, the pointer xd which pointed to the variable becomes invalid.
(*xd)
Here, you indirect through an invalid pointer. That's something that a program must never do. The behaviour of the program is undefined. The program is broken. Don't do this.

Related

Assigning a struct pointer value from struct vector

#include <iostream>
#include <vector>
using namespace std;
struct Sn {
int SnId;
double spentEnergy;
};
class Node {
//other stuff
private:
vector<Sn> SnRecord;
public:
int getBestSn(Sn* bestSn);
void someFunction();
};
int main()
{
Node nd;
nd.someFunction();
return 0;
}
void Node::someFunction() {
//adding some records in vector just for testing purpose
Sn temp;
temp.SnId = 1; temp.spentEnergy = 5;
SnRecord.push_back(temp);
temp.SnId = 2; temp.spentEnergy = 10;
SnRecord.push_back(temp);
temp.SnId = 2; temp.spentEnergy = 10;
SnRecord.push_back(temp);
cout << "Size of SnReocord is " << SnRecord.size() << endl;
//choosing best sn
Sn *bestSn;
int returnCode = -1;
returnCode = getBestSn(bestSn);
if (returnCode == 0){ //means there is a best SN
cout<< "Found best SN with id = "<< bestSn->SnId << endl;
}
else {
cout <<"NO SN "<< endl;
}
}
int Node::getBestSn(Sn* bestSn) {
int tblSize = (int)SnRecord.size();
if (tblSize == 0)
return -1;
//here i have to assign *bestSn a selected value from vector
//suppose SnRecord[2] is best Sn
cout << "Best sn id is " << SnRecord[2].SnId<< endl; //works OK,
bestSn = &SnRecord[2]; ///// giving me core dump ERROR in my own program but in this simplified version it only gives wrong value
return 0;
}
The output now is:
Size of SnReocord is 3
Best sn id is 2
Found best SN with id = 520004336
In my own program it gives me Core dump error, if I comment this line (and make proper other comments according to function call), the error is gone and simulation executes normally.
I saw examples with arrays, the work if a pointer is assigned a value in this way:
int numbers[5];
int * p;
p = &numbers[2]; //works OK.
but for vectors its not working. Or may be its problem of vector of structures, I'm unable to figure out. Any suggestions?
Ok actually the problem is solved by using suggestion of Sn* & bestSn. But I don't understand this solution. Why can't I pass a pointer variable and it saves a pointer value in it which latter could be accessed?

Changing the value of a int variable through pointers passed as arguments?

I want to modify values of some variables of a particular class by accessing address of these variables from another different class through a function. So, to access this address I try to pass pointers-to-variables as arguments to a function, where these pointers-to-variables will be set with the address of the variables. To learn how to do it, I'm trying to mimic in a simple program.
Here is my code:
#include <iostream>
using namespace std;
int numberA = 100;
int numberB = 200;
void referenceSetter(int *a, int *b)
{
*a = numberA;
*b = numberB;
}
void numberOutput()
{
cout << "A = " << numberA << endl;
cout << "B = " << numberB << endl;
}
int main() {
int *testA = 0;
int *testB = 0;
referenceSetter(testA, testB);
*testA = 30;
*testB = 40;
numberOutput();
return 0;
}
As you could see I declare numberA and numberB as global variables and set their values. The I try to get the address of these two variables through the function referenceSetter function and then after that I try to modify the values in those variables using the references. Apparently, I'm doing something wrong which leads to to have Unhandled Exception error exactly when I try to modify the values and try to set them as 30 and 40 resepectively.
Alternatively I tried the following approach:
#include <iostream>
using namespace std;
int numberA = 100;
int numberB = 200;
void referenceSetter(int *a, int *b)
{
a = &numberA;
b = &numberB;
}
void numberOutput()
{
cout << "A = " << numberA << endl;
cout << "B = " << numberB << endl;
}
int main() {
int *testA;
int *testB;
referenceSetter(testA, testB);
*testA = 30;
*testB = 40;
numberOutput();
return 0;
}
But this approach throws up the error uninitialized local variables testA and testB. Do I have to initialize pointers too?
Please help me find my mistake. Thanks.
The thing you're not understanding is that pointers are passed by value, just like any other variable. If you want the passed pointer to be changed, you need to pass a pointer to a pointer (or a reference to a pointer, but I'll leave that alone, as explaining references at this point will confuse you further).
Your main() is passing NULL pointers to referenceSetter(). The assignment *a = numberA copies the value of numberA (i.e. 100) into the memory pointed to by a. Since a is a NULL pointer, that has the effect of overwriting memory that doesn't exist as far as your program is concerned. The result of that is undefined behaviour which means - according to the standard - that anything is allowed to happen. With your implementation, that is triggering an unhandled exception, probably because your host operating system is detecting that your program is writing to memory that it is not permitted to write to.
If, after the call of referenceSetter() you want testA and testB to contain the addresses of numberA and numberB respectively, you need to change referenceSetter() to something like;
void referenceSetter(int **a, int **b)
{
*a = &numberA;
*b = &numberB;
}
This allows the values passed to be addresses of pointers. *a then becomes a reference to the pointer passed. &numberA compute the address of numberA, rather than accessing its value 100. Similarly for numberB.
The second change is to change main() so it calls the function correctly;
referenceSetter(&testA, &testB);
which passes the address of testA (and testB) to the function, so those pointers can be changed
You are trying to set the contents of address 0 to be equal to the other numbers, so when you're doing *a = numberA you're assigning a value of numberA to memory address 0.
Not sure, but I think what you're trying to achieve is this:
#include <iostream>
using namespace std;
int numberA = 100;
int numberB = 200;
void referenceSetter(int **a, int **b)
{
*a = &numberA;
*b = &numberB;
}
void numberOutput()
{
cout << "A = " << numberA << endl;
cout << "B = " << numberB << endl;
}
int main() {
int *testA = 0;
int *testB = 0;
referenceSetter(&testA, &testB);
*testA = 30;
*testB = 40;
numberOutput();
return 0;
}
This way, using pointers to pointers as arguments for referenceSetter(), you are actually modifying the address that your passed pointers are pointing to.
You are close, but the key is you need to pass the address of the value you want to set. You declare the values as int in main and pass the address by using the & operator:
int *testA = 0;
int *testB = 0;
referenceSetter(&testA, &testB);
*testA = 30;
*testB = 40;
numberOutput();
If you declare testA and testB as pointers in main and pass the pointer, the function gets a copy of the pointer instead of the address of the value you want to set.

C++ Pointers -- Weird Loop Behavior

From main, I am trying to call a prime function in mymath.cpp -- it has some
very strange behaviour that I do not understand. (Note, the algorithm doesn't work
yet -- but that's not what is strange to me.)
The strange thing is, if I comment out the line:
cout << "n:" << lastPrime->pnum <<"\n";
... in mymath.cpp, my loop in main only runs twice. If I leave it in, my loop in main runs all the way up to i = 50;
MAIN.CPP
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include "stat.h"
#include "mymath.h";
using namespace std;
int main()
{
for (int i = 3; i<= 50; i++)
{
if (isPrime(i))
{
cout << i << " is prime!\n";
}
else
{
cout << i << " is NOT prime\n";
}
}
return 0;
}
MYMATH.CPP
#include "mymath.h"
#include <math.h>
#include <iostream>
using namespace std;
prime two;
prime * lastPrime = &two;
prime * firstPrime = &two;
bool isPrime(long long n)
{
two.pnum=2;
prime * currentPrime = &two;
if ( n < 2)
return false;
long long squareRoot = sqrt(n);
while(true)
{
if (n % currentPrime->pnum==0)
{
//n is divisible by a prime number, nothing left to do.
return false;
}
else
{
//n is not divisible by a prime... check next one
{
if (currentPrime->pprime == 0 || currentPrime->pnum > squareRoot)
{
//this is prime
prime addPrime;
addPrime.pnum=n;
addPrime.pprime=0;
lastPrime->pprime=&addPrime;
lastPrime=&addPrime;
cout << "n:" << lastPrime->pnum <<"\n";
return true;
}
else
{
//may not be prime, check next
currentPrime = currentPrime->pprime;
}
}
}
}
return true;
}
The code has undefined behaviour as a local variable, named addPrime, is being used beyond its lifetime:
lastPrime->pprime=&addPrime;
lastPrime=&addPrime;
cout << "n:" << lastPrime->pnum <<"\n";
return true;
} // 'lastPrime' is now a dangling pointer because it holds the address
// of 'addPrime' whose lifetime has ended.
To correct, you need to dynamically allocate a prime using new instead. But, it appears (without the definition of prime I am uncertain) the code is building a list of primes encountered. Suggest using a std::vector<prime> to build the list and let it manage memory for you.
If a std::vector<prime> is not an option, for whatever reason, then ensure all instances of prime are dynamically allocated and not a mix of dynamically allocated instances and non-dynamically allocated instances (such as the global two) as it is illegal to delete an object not dynamically allocated.
Problems that come and go as you add or remove innocuous code almost always are the result of a bad pointer; sometimes it overwrites something that's important and sometimes it overwrites something that doesn't matter.
In this case, the bad pointer comes from taking the address of addPrime and saving it. At the end of the block addPrime goes away, and the pointer to it becomes invalid.

Segfault with std::list usage

I'm Java user coming over to C++, and I am having a hard time understanding what is going wrong with this statement. My program has been segfaulting anywhere I put the push_back command. So I'm wondering what exactly is going on.
class Process {
public:
int nice;
int arrivalTime;
int cpuBursts;
list<int> burstList;
Process() {
burstList.push_back(10); // Segfaults here...
}
};
Here is the full code:
#include<iostream>
#include<stdlib.h>
#include<fstream>
#include<list>
#include<string.h>
using namespace std;
int calcTimeslice(int priority);
int calcOriginalPrio(int nice);
int readFile(int ,char **);
int calcPrioBonus(int,int);
void tokenizeAndAdd(char *);
class Bursts {
public:
int isCPUBurst;
int time;
Bursts() {}
// Constructor to make it easier to add to list
Bursts(int tempIsCPU, int tempTime) {
isCPUBurst = tempIsCPU;
time = tempTime;
}
};
class Process {
public:
int nice;
int arrivalTime;
int cpuBursts;
list<int> burstList;
Process() {
burstList.push_back(10);
}
};
int main(int arg, char **argv) {
// This is if the file was not correctly read into the program
// or it doesnt exist ...
if(readFile(arg,argv)==-1) {
cout << "File could not be read. \n";
return -1;
}
//cout << "Original Calc Whatever: " << calcOriginal(19) << '\n';
return 0;
}
/*
* Calculates the timeslice based on the priority
*/
int calcTimeslice(int priority) {
double finalCalc;
// This is the given function in the prompt
finalCalc = ( (1 - (priority / 140)) * 290 + (.5) ) + 10;
// Cast to int, this will be a truncate
return ((int)finalCalc);
}
int readFile(int arg, char **argv) {
char *temp,*pointer;
int endOfFile = 1;
// While its not the end of the file
while(endOfFile) {
// Read in the input from stdin
fgets(temp,256,stdin);
// Check to see if this line had a * in it
if(*temp =='*')
endOfFile = 0;
else
tokenizeAndAdd(temp);
}
return 0;
}
void tokenizeAndAdd(char *string) {
char *token = strtok(string," \n");
int i = 0;
Process p;
while(token != NULL) {
cout << token << endl;
if(i>2) { // If it is odd (CPU burst)
if(i%2 == 1) {
int tempInt = atoi(token);
//p.burstList.push_back(tempInt);
}
else { // If it is even (IO burst)
int tempInt = atoi(token);
//p.burstLis.push_back(tempInt);
}
}
else if(i==0)
p.nice = atoi(token);
else if(i==1)
p.arrivalTime = atoi(token);
else if(i==2)
p.cpuBursts = atoi(token);
token = strtok(NULL," \n");
i++;
}
//cout << p.nice << " " << p.arrivalTime << " " << p.cpuBursts << "\n";
//i = 0;
//cout << p.burstList.size() << "\n";
// cout <<
//}
return;
}
/*
* Calculates and returns the original priority based on the nice number
* provided in the file.
*/
int calcOriginalPrio(int nice) {
double finalCalc;
// This is the given function from the prompt
finalCalc = (( nice + 20 ) / 39 ) * 30 + 105.5;
// Cast to int, this is a truncate in C++
return ((int)finalCalc);
}
/*
* Calculates the bonus time given to a process
*/
int calcPrioBonus(int totalCPU, int totalIO) {
double finalCalc;
// How to calculate bonus off of the prompt
if(totalCPU < totalIO)
finalCalc = ( (1 - (totalCPU / (double)totalIO)) * (-5)) - .5;
else
finalCalc = ( (1 - (totalIO / (double)totalCPU)) * 5) + .5;
// Cast to int
return ((int)finalCalc);
}
You are using temp uninitialized in the following code:
char *temp;
...
while(endOfFile) {
fgets(temp,256,stdin);
...
This can have any side effect, since it most likely destroys your stack or parts of the heap memory. It could fail immediately (when calling the fgets() function), it could fail later (as in your sample) or it could even run fine - maybe until you upgrade your OS, your compiler or anything else, or until you want to run the same executable on another machine. This is called undefined behaviour.
You need to allocate space for the temp variable, not a pointer only. Use something like
char temp[256];
...
while(endOfFile) {
fgets(temp,256,stdin);
...
For more information, see the fgets() documentation. The first parameter is a pointer to a char array - that is where fgets() will store the bytes which have been read. In your code, you pass an uninitialized pointer which means that fgets() will store the bytes to an undefined memory location - this is catched by the OS which terminates your application with a segmentation fault.
BTW: You should consider enabling pedantic warnings when compiling - I compiled with
g++ -Wall -pedantic -o list list.cpp
which gave me the following warning:
list.cpp: In function 'int readFile(int, char**)':
list.cpp:76:26: warning: 'temp' may be used uninitialized in this function [-Wuninitialized]
This is probably not the actual code with the error you report. But here is one of the problems with give you UB.
char *temp,*pointer; // uninicialized pointer char temp[1000]; could work?
int endOfFile = 1;
// While its not the end of the file
while(endOfFile) {
// Read in the input from stdin
fgets(temp,256,stdin);
The last function call will read a maximum of 256 bytes from stdin and will write it in the memory pointed by pointer tmp. So, you need to first "prepare" that memory. But with char *tmp; you only define a pointer, with no defined value, that is, with point to some possible unexisting or illegal/inaccessible for you memory. In contrary, char tmp[1000]; will define in the "stack memory" a block of 1000 bytes, with you can point to using simple the variable tmp. Hope this is clear for you.
EDIT:
I don't know why that would change the behavior of the list,
You are right. That is Undefined Behavior (UB). When you write in some unknown memory (pointed by an uninitialized pointer) you may overwrite data or even code that will broke somewhere the correct function of your program in an unpredicted way.
You will need to learn more about pointers but better you use std::string, and look how parse your file using string and stringstream. That will manage for you the memmory,

Getting segmentation fault after destructor

I'm making a small file reading and data validation program as part of my TAFE (a tertiary college) course, This includes checking and validating dates.
I decided that it would be best done with a seperate class, rather than integrating it into my main driver class.
The problem is that I'm getting a segmentation fault(core dumped) after my test program runs. Near as I can tell, the error occurs when the program terminates, popping up after the destructor is called. So far I have had no luck finding the cause of this fault, and was hoping that some enlightened soul might show me the error of my ways.
date.h
#ifndef DATE_H
#define DATE_H
#include <string>
using std::string;
#include <sstream>
using std::stringstream;
#include <cstdlib>
using std::exit;
#include <iostream>
using std::cout;
using std::endl;
class date {
public:
explicit date();
~date();
bool before(string dateIn1, string dateIn2);
int yearsBetween(string dateIn1, string dateIn2);
bool isValid(string dateIn);
bool getDate(int date[], string dateIn);
bool isLeapYear(int year);
private:
int days[];
};
#endif
date.cpp
#include "date.h"
date::date() {
days[0] = 31;
days[1] = 28;
days[2] = 31;
days[3] = 30;
days[4] = 31;
days[5] = 30;
days[6] = 31;
days[7] = 31;
days[8] = 30;
days[9] = 31;
days[10] = 30;
days[11] = 31;
}
bool date::before(string dateIn1, string dateIn2) {
int date1[3];
int date2[3];
getDate(date1, dateIn1);
getDate(date2, dateIn2);
if (date1[2] < date2[2]) {
return true;
} else if (date1[1] < date2[1]) {
return true;
} else if (date1[0] < date2[0]) {
return true;
}
return false;
}
date::~date() {
cout << "this is for testing only, plox delete\n";
}
int date::yearsBetween(string dateIn1, string dateIn2) {
int date1[3];
int date2[3];
getDate(date1, dateIn1);
getDate(date2, dateIn2);
int years = date2[2] - date1[2];
if (date1[1] > date2[1]) {
years--;
}
if ((date1[1] == date2[1]) && (date1[0] > date2[1])) {
years--;
}
return years;
}
bool date::isValid(string dateIn) {
int date[3];
if (getDate(date, dateIn)) {
if (date[1] <= 12) {
int extraDay = 0;
if (isLeapYear(date[2])) {
extraDay++;
}
if ((date[0] + extraDay) <= days[date[1] - 1]) {
return true;
}
}
} else {
return false;
}
}
bool date::getDate(int date[], string dateIn) {
string part1, part2, part3;
size_t whereIs, lastFound;
whereIs = dateIn.find("/");
part1 = dateIn.substr(0, whereIs);
lastFound = whereIs + 1;
whereIs = dateIn.find("/", lastFound);
part2 = dateIn.substr(lastFound, whereIs - lastFound);
lastFound = whereIs + 1;
part3 = dateIn.substr(lastFound, 4);
stringstream p1(part1);
stringstream p2(part2);
stringstream p3(part3);
if (p1 >> date[0]) {
if (p2>>date[1]) {
return (p3>>date[2]);
} else {
return false;
}
return false;
}
}
bool date::isLeapYear(int year) {
return ((year % 4) == 0);
}
and Finally, the test program
#include <iostream>
using std::cout;
using std::endl;
#include "date.h"
int main() {
date d;
cout << "1/1/1988 before 3/5/1990 [" << d.before("1/1/1988", "3/5/1990")
<< "]\n1/1/1988 before 1/1/1970 [" << d.before("a/a/1988", "1/1/1970")
<<"]\n";
cout << "years between 1/1/1988 and 1/1/1998 ["
<< d.yearsBetween("1/1/1988", "1/1/1998") << "]\n";
cout << "is 1/1/1988 valid [" << d.isValid("1/1/1988") << "]\n"
<< "is 2/13/1988 valid [" << d.isValid("2/13/1988") << "]\n"
<< "is 32/12/1988 valid [" << d.isValid("32/12/1988") << "]\n";
cout << "blerg\n";
}
I've left in some extraneous cout statements, which I've been using to try and locate the error.
I thank you in advance.
Change:
private:
int days[];
to:
private:
int days[12];
The problem is that you never actually initialize the days field in the type date. This means that when you are setting the values in the constructor you are accessing uninitialized memory.
You need to explicitly initialize the days value in some way. The easiest fix is to use a vector for the type or to hard code the size of the array to 12.
private:
int days[12];
Or
private:
std:vector<int> days;
...
date::date() {
days.push_back(31);
days.push_back(28);
...
}
You don't say which compiler you are using, but if I compile this code using g++ with the -Wall and -pedantic flags:
struct S {
int a[];
};
int main() {
S s;
}
I get the warning message:
warning: ISO C++ forbids zero-size array 'a'
The moral is that you should always compile using as many compiler warnings as possible - it can save you mountains of time and result in more correct code.
int days[];
This is a non-standard extension. You must specify a size for the array, such as:
static const MonthCount = 12;
int days[MonthCount];
To actually have an array to use. Otherwise you have a "zero-sized array" (not standard!). Your program is tromping over memory every time you use any element of your current array.
I agree with the previous answers to this question, but I would add the rationale for their correctness:
Segmentation faults are caused whenever you attempt to access memory you are not allowed to access.
http://en.wikipedia.org/wiki/Segmentation_fault
You were not allowed to access "days[0]" through days "[11]" because the computer had not given the "days[]" variable that you declared enough memory to hold any elements, thus when you tried to access said elements, it threw a segfault.
Any variables not declared with the "new" operator are placed on the "stack," which is a contiguous chunk of memory the computer has sectioned away for use by the program. In order to keep everything stored in the stack contiguous, the computer will only give exactly the amount memory you require for you to use whenever you request it, so that if you request to create an int, for example, it will only give you enough memory to store that single int.
When you wrote the line int days[]; the computer attempted to evaluate how much memory it would require, assessed it as an empty array, and gave you enough memory to store said empty array. Because the computer did not give your array any extra space beyond what was needed for an empty array, it knew that the memory you tried to access in that array had not been assigned to it, so it threw a segmentation fault and crashed.
If you have not yet learned about the "stack" and "heap" in your computer science class, then sorry if this is a bit overwhelming, but I perhaps overcomplicated things, and I think you likely soon will.