C++ Pointers -- Weird Loop Behavior - c++

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.

Related

Strange C++ output with boolean pointer

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.

Flipping a Coin until 3 heads appear

Write a program that simulates flipping a coin repeatedly and continues until three consecutive heads are tossed.
#include <iostream>
#include <cmath>
#include <string>
#include <cstdlib>
#include "random.h"
using namespace std;
enum CoinSide {heads, tails};
CoinSide FlipCoin(int flip);
int main(){
int flip;
int heads = 0;
int total_flips = 0;
while( heads < 3){
total_flips++;
if(FlipCoin(flip) == heads){
heads++;
} else{
heads = 0;
}
}
cout << "it took " << total_flips << "to get 3 consecutive heads. " << endl;
}
CoinSide FlipCoin(int flip) {
if (randomChance(0.50)) {
return "heads";
} else {
return "tails";
}
}
Now I am getting an unknown error, when I run this code, anyone know why it wont run>?
FlipCoin returns a boolean (integral) value, and comparison against a const char* is illegal. "heads" and "tails" are just that.
You can return a std::string to perform a comparison, but I'd suggest you have an enum CoinSide {HEADS, TAILS}; and return that instead.
CoinSide FlipCoin(int flip) {
if (randomChance(0.50)) {
return HEADS;
}
return TAILS;
}
and
if (FlipCoin(flip) == HEADS)
Apart from the above answer:
Please do yourself and anybody who might have to look over your code a favor by never ever using the same name for different things and try to use those different things in the same context. In this case I'm talking about
enum CoinSide {heads, tails}; // <- This
CoinSide FlipCoin(int flip);
int main(){
int flip;
int heads = 0; // <- in combination with this! Because:
int total_flips = 0;
while( heads < 3){
total_flips++;
if(FlipCoin(flip) == heads){
// You might think you're comparing
// FlipCoin(int)::CoinSide vs. CoinSide::heads
// But(!) you compare
// FlipCoint(int)::CoinSide vs. main::heads
// The very main::heads you're going to increase now.
heads++;
} else{
heads = 0;
}
} // Will never terminate.
cout << "it took " << total_flips << "to get 3 consecutive heads. " << endl;
}
If you use constant values which mean something you should
a) make them visually stand out, e.g. using HEADS or TAILS instead of heads or tails in enums.
b) never ever give two things the same name and (try to) use them in the same context.
This will save you some serious case of head scratching in the future.

Run time error for dynamic memory allocation in C++

I am a newbie for OOP concepts and while trying to solve Project Euler Problem 7, to find 10001th prime number, I tried to do it using a class but encountered 2 major errors.
instantiating the class prime_n
initializing its argument
I have posted the code here for reference:
#include<iostream>
#include<cstdio>
using namespace std;
class prime_n
{
int j,k;
int n;
int *store;
public:
prime_n(int num)
{
n=num;
store[n];
}
static int isPrime(int j)
{
for(int i=2;i*i<=j;i++)
{
if(j%i==0) return 0;
}
return 1;
}
void find_n()
{
for(int i=0;i<n;i++)
{
store[i]=0;
}
store[0]=2;
j=3;
k=1;
while(store[n-1]==0)
{
if(isPrime(j)) store[k++]=j;
j+=2;
}
}
int get_num()
{
int value=store[n-1];
return value;
}
};
int main()
{
int num, req_num;
printf("Enter the position at which prime number is to be found ");
scanf("%d",&num);
printf("\nnumber = %d",num);
prime_n p = new prime_n(num);
req_num = p.get_num();
printf("The required prime number is %d\n",req_num);
return 0;
}
It would be a great help if someone could help me figure out where I am actually going wrong. Thanks a lot in advance!
Use
prime_n p(num);
or (not recommended in this particular case)
prime_n * p = new prime_n(num);
// some other code
req_num = p->get_num(); // note the -> operator replacing . in case of pointers
delete p;
The first case declares p on stack and it is automatically deallocated when the program leaves the scope (main function in this case)
The second one allocates space on heap and p is the pointer to it. You have to deallocate the memory manually.
As for your second question, the C++ way would be
#include <iostream>
...
int num;
std::cout << "Enter the position at which prime number is to be found "
std::cin >> num;
std::cout << std::endl << "Number = " << num << std::endl;
You provide a constructor:
prime_n(int num)
{
n=num;
store[n];
}
I think you are under the impression that store[n] creates an array with n elements, but that is not so; it attempts to access the (n+1)th element of an an array. Since store does not point anywhere (we are in the constructor, after all), the program crashes.
You probably want to write store = new int[num] instead.
And then I cannot see any call to find_n() originating from get_num() which is called in main(), so that your program would for now just return a random value.

C++, using stack.h read a string, then display it in reverse

For my current assignment, I have to use the following header file,
#ifndef STACK_H
#define STACK_H
template <class T, int n>
class STACK
{
private:
T a[n];
int counter;
public:
void MakeStack() {
counter = 0;
}
bool FullStack() {
return (counter == n) ? true : false ;
}
bool EmptyStack() {
return (counter == 0) ? true : false ;
}
void PushStack(T x) {
a[counter] = x;
counter++;
}
T PopStack() {
counter--;
return a[counter];
}
};
#endif
To write a program that will take a sentence, store it into the "stack", and then display it in reverse, and I have to allow the user to repeat this process as much as they want. The thing is, I am NOT allowed to use arrays (otherwise I wouldn't need help with this), and am finding myself stumped.
To give an idea of what I am attempting, here is my code as of posting, which obviously does not work fully but is simply meant to give an idea of the assignment.
#include <iostream>
#include <cstring>
#include <ctime>
#include "STACK.h"
using namespace std;
int main(void)
{
auto time_t a;
auto STACK<char, 256> s;
auto string curStr;
auto int i;
// Displays the current time and date
time(&a);
cout << "Today is " << ctime(&a) << endl;
s.MakeStack();
cin >> curStr;
i = 0;
do
{
s.PushStack(curStr[i]);
i++;
} while (s.FullStack() == false);
do
{
cout << s.PopStack();
} while (s.EmptyStack() == false);
return 0;
} // end of "main"
UPDATE
This is my code currently
#include <iostream>
#include <string>
#include <ctime>
#include "STACK.h"
using namespace std;
time_t a;
STACK<char, 256> s;
string curStr;
int i;
int n;
// Displays the current time and date
time(&a);
cout << "Today is " << ctime(&a) << endl;
s.MakeStack();
getline(cin, curStr);
i = 0;
n = curStr.size();
do
{
s.PushStack(curStr[i++]);
i++;
}while(i < n);
do
{
cout << s.PopStack();
}while( !(s.EmptyStack()) );
return 0;
You're on the right track, but you shouldn't be looping until the stack is full -- there are no guarantees curStr consists of at least 256 characters. Instead, loop like as follows...
int n = curStr.size();
do {
s.PushStack(curStr[i++]);
} while (i < n);
Now, you should really not write <bool-expr> == false or <bool-expr> == true... instead, merely write !<bool-expr> and <bool-expr>, respectively. You don't need all of your auto storage specifiers on the local variables, either. Your professor should also look into using the constructor rather than using MakeStack.
edit: It appears you had some trouble translating my code. You only need to i++ once per loop -- this increments our position in the string. As you are doing it now, you are actually incrementing the position twice and thus only pushing every other character.
Use a linked list instead of array in stack.
In the linked list, always store the tail pointer of your list's last node. Each node maintains a reference to your prev node.
A <--- B <---- C (tail)
push:
A <--- B <---- C <---- D (tail)
pop:
A <--- B <---- C (tail)
// D is popped out
when the tail == null, you know it is an empty stack

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.