#include<iostream>
using namespace std;
#include<cstring>
struct stringy
{
char * str;
int ct;
};
void set(stringy & stringa, char ar[]);
void show(stringy & stringa);
int main()
{
stringy beany;
char testing[] = "Reality isn't what is used to be.";
set(beany, testing);
show(beany);
return 0;
}
void set(stringy & stringa, char * ar)
{
char * ps = new char[strlen(ar) + 1];
stringa.str = ps;
strcpy(ar,ps);
cout << strlen(stringa.str);
stringa.ct++;
delete [] ps;
}
void show(stringy & stringa)
{
for(int i = 0; stringa.str[i] != '\0'; i++)
{
cout << stringa.str[i];
}
}
This is my code. It's part of an exercise. I was given the body of the main function as asked to write functions that did the requested task.
locates space to hold copy of testing,
sets str member of beany to point to the
new block, copies testing to new block,
and sets ct member of beany
My issue is with the set function. I feel as though i have satisfied the criteria, the strlen is there because i am trying to figure out what is going on... it returns 0. then the program exits.
There are a lot of problems with this code, among which:
strcpy(ar, ps);
This copies ps to ar, not the other way around. You want:
strcpy(ps, ar);
This error would have been detected by the compiler if the const qualifier were used as it should have been.
Additionally, the delete[] ps at the end of set() should not be there.
Finally, I'm not sure what the purpose of the ct field is, so I can't tell you what it should be, but incrementing an uninitialized field is certainly wrong.
Related
const char * u8_to_bstr(const uint8_t & u8) {
static char s[9]; // space for 8-char string
s[8] = 0; // terminate string
char * sp = s;
for (uint8_t xbit = 0b10000000; xbit > 0; xbit >>= 1) {
cout << s << endl;
*(sp++) = ((u8 & xbit) == xbit) ? '1' : '0';
}
return s;
}
I encountered this piece of code studying that converts a uint8 to a string representing its binary. My question is, why do we need the static qualifier for static char s[9]? When I remove the static qualifier I get some very strange behavior but I don't understand why.
The function returns s, which is declared on the stack of this function. Were it not static, it would go out of scope, effectively disappear, once the function returns because all the storage on the stack is made available for reuse once a function returns. By making it static, it’s forced to have a persistent address in memory. However, it’s still bad design - if you call this function from multiple threads, they’ll fight with each other for use of the static memory space.
To expand on what #VorpalSword offered in their answer, it doesn't have to be static. Instead you could dynamically allocate the array. This dynamically allocated memory will remain valid after u8_to_bstr exits.
const char * u8_to_bstr(const uint8_t & u8) {
const char *s = new char[9]; // space for 8-char string
s[8] = 0; // terminate string
char *sp = s;
for (uint8_t xbit = 0b10000000; xbit > 0; xbit >>= 1) {
cout << s << endl;
*(sp++) = ((u8 & xbit) == xbit) ? '1' : '0';
}
return s;
}
It's a remarkably small change to your code, but it does have implications for how your program works, and you do have to remember later to free up this memory.
delete[] variable_holding_results_of_u8_to_bstr;
This is a simple view os storing your data in memory so that it will remain usable after u8_to_bstr finishes its work without using static. It is by no means the only way or the best way.
In good practice, you'd make use of std::unique_ptr and std::vector rather than manually allocating and deleting arrays. Here is a quick view of your code translated to use these tools. Please note I've added a print_vec helper function.
#include <iostream>
#include <vector>
#include <memory>
using std::vector;
using std::unique_ptr;
using std::make_unique;
void print_vec(unique_ptr<vector<char>> const& v);
unique_ptr<vector<char>> u8_to_bstr(const uint8_t & u8);
int main() {
auto r = u8_to_bstr(45);
print_vec(r);
}
void print_vec(unique_ptr<vector<char>> const& v) {
for (auto ch : *v) {
std::cout << ch;
}
std::cout << std::endl;
}
unique_ptr<vector<char>> u8_to_bstr(const uint8_t & u8) {
auto s = make_unique<vector<char>>(9, '\0');
auto sp = s->begin();
for (uint8_t xbit = 0b10000000; xbit > 0; xbit >>= 1) {
print_vec(s);
*(sp++) = ((u8 & xbit) == xbit) ? '1' : '0';
}
return s;
}
You will almost certainly need to compile this specifying the C++14 or C++17 standards. If you wish to research the types and functions introduced, cppreference.com is a good site, and will tell you what C++ standards types/fucntions were introduced in.
I am a bit puzzled by this one. Everything has been fine so far with using SQLite but now I am trying to store my query results in a simple struct. When I do this in my callback, all my data looks great in my SQLItems vector but as soon as the callback exits, my SQLItems vector holding my rows of data is suddenly corrupted. Any ideas what could be causing this?
// Simple struct to hold column name and row data
struct SQLrow {
char * Column;
char * Data;
};
// static Vector to hold SQL rows
static std::vector<SQLrow> SQLItems;
...
// static callback that handles placing query results into structs and into SQLItems vector
// SQLItems column/row data gets corrupted after this function exits
static int countTablesCallback(void *data, int count, char **rows, char **azColName) {
int i;
for (i = 0; i < count; i++) {
SQLrow newItem = { azColName[i] ,rows[i] };
SQLItems.push_back(newItem);
}
*static_cast<std::vector<SQLrow>*>(data) = SQLItems; // Tried this too but throws an exception
return 0;
}
I also thought maybe it is only possible to statically cast from the callback to save the vector but that is throwing an exception as well. Stumped here. Thanks for any advice!
Your vector is fine, the static_cast makes no sense there, unless data is actually used as an out parameter. Your problem is, most likely, that SQLrow holds char pointer and SQLite deletes the pointed-to strings after the callback returns. Changing your class to
struct SQLrow {
std::string Column;
std::string Data;
};
should solve the problem.
Just looking at the code, it appears that the data pointed to by rows will be invalidated/destroyed/changed once the callback returns. So you can't retain those pointers for later use, and will have to make a copy of the data.
One easy way is to change Column and Data from char * to std::string. Failing that, you'll have to do some sort of manual memory management (allocate space with new, then delete it later) which is error prone and not really advisable these days.
In my opinion, there are very few case in which you want/need to use raw string in c++ and yours isn't one of those. By the way I hope this will help you or someone else in some way:
#include <vector>
#include <stdio.h>
#include <string.h>
#include <iostream>
struct SQLrow {
char* Column;
char* Data;
};
void your_callback(int count, char **rows, char **azColName) {
std::vector<SQLrow> rows_list;
for (int i = 0; i < count; i++) {
/* Uncomment this if you want
your copy of the strings. If you
use this, don't forget to free the
memory yourself with delete[] s1 and
s2.
size_t s1_len = strlen(rows[i]);
size_t s2_len = strlen(azColName[i]);
char* s1 = new char [sizeof(char) * (s1_len + 1)];
char* s2 = new char [sizeof(char) * (s2_len + 1)];
memcpy(s1, rows[i], s1_len);
s1[s1_len] = '\0';
memcpy(s2, azColName[i], s2_len);
s2[s2_len] = '\0';
SQLrow r = { s1, s2 }; */
SQLrow r = { rows[i], azColName[i] };
rows_list.push_back(r);
}
// test the result
for (int i = 0; i < count; i++) {
SQLrow r = rows_list.at(i);
std::cout << "rows:" << r.Column << " azColName:" << r.Data << std::endl;
}
}
// this 2 lines are just for simulating the data
// you will get this 'warning: ISO C++ forbids converting a string constant to char*''
char* rows[] = {"row1", "row2" , "row3" };
char* colName[] = {"name1", "name2", "name3" };
int main()
{
your_callback(3, rows, colName);
return 0;
}
When I run this program sr1, sr2, sr3, sr4 objects are created and values are assigned to corresponding variables. But in sr5 object, the name remains blank while the roll_no percentage shows the correct value.
When change the value of
int MAX = 5;
to
int MAX = 6;
everything works fine.
Here is my code:
const int MAX = 5;
const int FREE = 0;
const int OCCUPIED = 1;
int flag = 0;
using namespace std;
void warning()
{
cout<<"\n------All memory occupied------"<<endl;
exit(1);
}
class student_rec
{
private:
char name[25];
int roll_no;
float percentage;
public:
student_rec(char *n, int r, float per)
{
strcpy(name, n);
roll_no = r;
percentage = per;
}
student_rec()
{
}
void set_rec(char *n, int r, float per)
{
strcpy(name, n);
roll_no = r;
percentage = per;
}
void show_rec()
{
cout<<"\n-------------------\n";
cout<<"Name= "<<name<<endl;
cout<<"Roll number= "<<roll_no<<endl;
cout<<"Percentage= "<<percentage<<endl;
}
void *operator new (size_t sz);
void operator delete (void *d);
};
struct memory_store
{
student_rec obj;
int status;
};
memory_store *m = NULL;
void *student_rec::operator new (size_t sz)
{
int i;
if(flag == 0)
{
m = (memory_store *) malloc(sz * MAX);
if(m == NULL)
warning();
for(i=0; i<MAX; i++)
m[i].status = FREE;
flag = 1;
m[0].status = OCCUPIED;
return &m[0].obj;
}
else
{
for(i=0; i<MAX; i++)
{
if(m[i].status == FREE)
{
m[i].status = OCCUPIED;
return &m[i].obj;
}
}
warning();
}
}
void student_rec::operator delete (void *d)
{
if(d == NULL)
return;
for(int i=0; i<MAX; i++)
{
if(d == &m[i].obj)
{
m[i].status = FREE;
strcpy(m[i].obj.name, "");
m[i].obj.roll_no = 0;
m[i].obj.percentage = 0.0;
}
}
}
int main()
{
student_rec *sr1, *sr2, *sr3, *sr4, *sr5, *sr6, *sr7;
sr1 = new student_rec("sandeep", 21, 78);
sr1->show_rec();
sr2 = new student_rec("sachin", 21, 78);
sr2->show_rec();
sr3 = new student_rec("sapna", 21, 78);
sr3->show_rec();
sr4 = new student_rec("vipin", 21, 78);
sr4->show_rec();
sr5 = new student_rec("niraj", 21, 78);
sr5->show_rec();
sr6 = new student_rec; // error all memory occupied.
return 0;
}
I run this code on linux machine.
This is terrible code. It is totally unaware of the C++ object model. Forget it and start with a good introductory book, that explains the object lifecycle, and how to properly create new objects.
More explanations about what goes wrong: flaw 1
The problem is in student_rec::operator new (). This line:
m = (memory_store *) malloc(sz * MAX);
let you think that m points to some valid array of memory_store objects. Unfortunately, the C malloc() is used to allocate raw memory. There are thus no valid objects in that memory. Otherwise said, the objects pointed to by m are in an unknown dirty state.
Later, the line
m[i].status = FREE;
handles the objects pointed by m as if they were already valid. This is undefined behavior. If you don't allocate objects the C++ way (e.g. new instead of malloc() ) you would first need to create them with a placement new.
Now for your simple object trivial object this will not cause too many damages. There's yet another flaw.
Even more explanations about what goes wrong: fatal flaw 2
There is a second serious problem: malloc only allocates sz * MAX bytes. As the operator is overloaded for student_rec, it will be called with sz being sizeof(student_rec). But your code assumes that it is sizeof(memory_store), so that the allocated memory is at least sizeof(int)*n bytes too short !!
This is why increasing MAX (and thus allocating more memory than needed for your 5 objects) seems to work.
Other remarks
Using global variables as you did, exposing m to the outside world, is very dangerous and error prone. Suppose that in some other functions you'd like to use a local variable m, but forget to declare it; you could corrupt your data structure much faster than you'd expect ! You'd better make it a private static member of student_rec.
Forget about fixed char arrays for storing C strings. If a name would be longer than expected, you'd get another serious problem that is difficult to spot (strcpy could result in memory corruption in such case). If you code in C++, take advantage of string in order not to worry about such details :-)
Stylistic remark: why not make flag a boolean and use true & false instead of 0 and 1 ?
Stylistic remark: The warning() function has a misleading name: warning() suggests that you issue a warning and continue. Why not giving it a self-documenting name like for example fatal_error() or warning_and_exit()
I have tried to obtain 2 pointers from a function and print it in main. the vague thing is one pointer seems to have recovered its values, while the other hasn't. And both the pointers, have the correct value inside the calling function, just before returning as well. Please tell me if you can identify any programmatic error that is preventing me from getting the right answer.
#include<iostream>
#include<fstream>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
using namespace std;
double* readctrls()
{
fstream inputs;
inputs.open("input_coods.txt");
int nol = 0,i = 0;
string line,temp,subtemptrans,subtemprots;
while(getline(inputs,line))
{
++nol;
}
// cout<<nol<<endl;
inputs.close();
inputs.open("input_coods.txt");
string *lines = new (nothrow) string[nol];
double* trans = new double[nol];
double* rots = new double[nol];
trans[0] =float(nol);
for(int i = 0; i<nol ; i++)
{
getline(inputs,lines[i]);
// cout<<lines[i]<<endl;
temp = lines[i];
// cout<<temp<<endl;
for(int j = 0; j<temp.length() ; j++)
{
if(temp.at(j) == ' ')
{
subtemptrans = temp.substr(0,j);
subtemprots = temp.substr(j+1,temp.length()-j);
// cout<<subtemprots<<endl;
*(trans+i+1) = ::atof(subtemptrans.c_str());
*(rots+i) = float(atoi(subtemprots.c_str()));
// cout<<rots[i]<<endl;
}
}
}
inputs.close();
// cout<<rots[2]<<endl;
return(rots,trans);
}
int main()
{
double *trans,*rots;
(rots,trans) = readctrls();
// cout<<sizeof(trans)<<endl;
for(int i=0;i<trans[0];i++)
{
cout<<*(trans+i)<<endl;
cout<<*(rots+i)<<endl;
}
}
The value of Trans is written fine in the memory and is perfectly retained from the main(). But the rots is giving garbage values of the order (e^-42). Please help me here.
C++ is neither Python nor Lua.
You can't return multiple values from a function.
return rots, trans;
This is the comma operator - evaluates its operands and yields the last (rightmost) one.
(rots, trans) = readctrls();
Likewise, this assigns to trans only, rots will be uninitialized.
Solution: you can either return a struct containing the two pointers, or pass them by reference, or whatever...
struct Foo {
double *rots;
double *trans;
};
Foo readctrls()
{
// ...
Foo r;
r.rots = rots;
r.trans = trans;
return r;
}
or:
void readctrls(double *&r, double *&t)
{
// ...
r = rots;
t = trans;
}
Other remarks:
Don't use raw arrays. std::vector<T> is generally preferred over T * in C++.
It's super wasteful to read the entire file just in order to count the lines, then read it once again to actually parse its contents. If you used an std::vector<double>, you could just vector.push_back(some_double); as you go along the lines, so you wouldn't have to walk through the file twice (you know, I/O is expensive, especially if the file is large).
You never delete the pointers that you allocate using new - here your program leaks memory.
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,