why strcat_s causing problems - c++

I'm facing problem that I get random chars output instead of getting first and mid and last name combined which is the purpose of the program and when I run the debugger it says that the problem in strcat_s but I don't know what's the problem with it
#include <iostream>
#include <string.h>
class name {
private:
char first[20], mid[20], last[20];
public:
name();
name(const char*, const char*, const char*);
~name();
char* show();
};
name::name()
{
first[0] = mid[0] = last[0] = '\0';
}
name::name(const char* f, const char* m, const char* l)
{
size_t lenF = strlen(f), lenM = strlen(m), lenL = strlen(l);
if (strlen(f) > 20) lenF = 20;
else if (strlen(m) > 20) lenM = 20;
else if (strlen(l) > 20) lenL = 20;
strncpy_s(first, f, lenF);
strncpy_s(mid, m, lenM);
strncpy_s(last, l, lenL);
}
name::~name()
{
std::cout << "distructing..." << std::endl;
}
char* name::show()
{
char temp[62];
strcpy_s(temp, first);
strcat_s(temp, " ");
strcat_s(temp, mid);
strcat_s(temp, " ");
strcat_s(temp, last);
return temp;
}
int main()
{
name a("kinan", "fathee", "ayed");
std::cout << a.show() << std::endl;
}

Your logic for returning the full name is incorrect. You have a local variable temp and you are returning a reference to that variable. However, this variable is destroyed once show() function is completed. So, in your main function you have a reference but its pointing to something that is already destroyed. That's why you will see random characters when you print it. Here is the solution to your problem. You need to create a dynamic array i.e a pointer so that it does not get destroyed.
char *name::show()
{
int size = strlen(first) + strlen(mid) + strlen(last) + 3;
char *temp = new char[size];
strcpy_s(temp, size, first);
strcat_s(temp, size, " ");
strcat_s(temp, size, mid);
strcat_s(temp, size, " ");
strcat_s(temp, size, last);
return temp;
}
int main()
{
name a("kinan", "fathee", "ayed");
char *temp = a.show();
std::cout << temp << std::endl;
delete[] temp;
}
Edit: In your original code, if you print temp at the end of show function before returning it, you will see that temp contains full name.
Edit: Temp is a local variable. Every local variable is destroyed at the end of the function's execution. In the suggested solution, I am creating an array dynamically on the heap. When we dynamically create an array, it's not removed from the heap automatically. So, when I return a reference to that array and use it in main it still works.
Edit:
I have added delete[] in main function to deallocate memory.

Should be reserved 1 character for '\0', therefore you need to write strncpy_s(first, f, lenF - 1);

Related

C++ String and Pointers Manipulation

Suppose I have this data structure in C++ :
struct Stash {
int size; // Size of each space
int quantity; // Number of storage spaces
int next; // Next empty space
// Dynamically allocated array of bytes:
unsigned char* storage;
// Functions!
void initialize(int size);
void cleanup();
int add(const void* element);
void* fetch(int index);
int count();
void inflate(int increase);
};///:~
void Stash::initialize(int sz) {
size = sz;
quantity = 0;
storage = 0;
next = 0;
}
int Stash::add(const void* element) {
if(next >= quantity) // Enough space left?
inflate(increment);
// Copy element into storage,
// starting at next empty space:
int startBytes = next * size;
unsigned char* e = (unsigned char*)element;
for(int i = 0; i < size; i++){
storage[(startBytes + i)] = e[i];
}
next++;
return(next - 1); // Index number
}
void* Stash::fetch(int index) {
// Check index boundaries:
assert(0 <= index);
if(index >= next)
return 0; // To indicate the end
// Produce pointer to desired element:
int value = (index*size);
return &(storage[value]);
}
int Stash::count() {
return next; // Number of elements in CStash
}
void Stash::inflate(int increase) {
assert(increase > 0);
int newQuantity = quantity + increase;
int newBytes = newQuantity * size;
int oldBytes = quantity * size;
unsigned char* b = new unsigned char[newBytes];
for(int i = 0; i < oldBytes; i++)
b[i] = storage[i]; // Copy old to new
delete []storage; // Old storage
storage = b; // Point to new memory
quantity = newQuantity;
}
void Stash::cleanup() {
if(storage != 0) {
cout << "freeing storage" << endl;
delete []storage;
}
} ///:~
Suppose now I use the data structure to memorize strings in this way :
int main(){
Stash* st1 = new Stash;
st1->initialize(sizeof(string));
string s1 = "This is a GOOD morning";
st1->add(&s1);
string s2 = "This is a BAD morning";
st1->add(&s2);
string* s3;
s3 = static_cast<string*> (st1->fetch(0));
cout << *s3 << endl;
string* s3;
s3 = static_cast<string*> (st1->fetch(1));
cout << *s3 << endl;
st1->cleanup();
delete st1;
return 0;
}
It Works!!! This is the output:
This is a GOOD morning
This is a BAD morning
But in this other way:
int main(){
Stash* st1 = new Stash;
st1->initialize(sizeof(string));
string s1 = "This is a GOOD morning";
st1->add(&s1);
s1 = "This is a BAD morning";
st1->add(&s1);
string* s3;
s3 = static_cast<string*> (st1->fetch(0));
cout << *s3 << endl;
string* s4;
s4 = static_cast<string*> (st1->fetch(1));
cout << *s4 << endl;
st1->cleanup();
delete st1;
return 0;
}
It doesn't work. This is the output:
This is a BAD morning
This is a BAD morning
So, what happened in the machine when I try to use the same reference?
I have tried with other datatypes and it works well.
The first use of s1 invokes the constructor:
string s1 = "This is a GOOD morning";
You then add the address of s1 to the Stash. Next you assign a new value to s1:
s1 = "This is a BAD morning";
This doesn't create a new string -- it invokes the assignment operator which replaces the same string object with a new value. You then save another copy of the address of s1:
st1->add(&s1);
If you look at the data in st1 then you'll see you have two copies of the same pointer, both pointing to s1. This is expected. In the first case you are storing pointers to two different objects which contain different values.
Your code copies the bytes making up a std::string container (NOT the characters that are in the string data). This probably consists of a pointer to the string data, plus a size and capacity.
When you write s1 = "stuff", the std::string internally allocates new memory, so its previous internal pointer is now invalid.
Then you retrieve that previous internal pointer from your data structure and try to use it, causing undefined behaviour.
If your intent is to save the characters in the string then you need to add s1.c_str() instead of &s1.
If your intent is to store a copy of any object then you need to invoke the copy constructor to create a copy; not do a bitwise copy as you are currently doing. You could also invoke a move constructor or move assignment operator if your intent is to store the object and not leave the original object behind.
In your second approach, you have used address of s1 to be stored in stack. And you are not copying the contents within the stack, so when you change s1 to have a different content earlier content also changes, because you essentially pushed the pointer not the copy of the content.
For example, if you do the following (copying the content to a new string to be used for push), this works:
string s1 = "This is a GOOD morning";
st1->add(new string(s1));
s1 = "This is a BAD morning";
st1->add(new string(s1));

Reading int value from char array after converting to void pointer

I'm trying to build memory chunks of generic data types, but I'm getting garbage when printing the result.
void Read(void* _data, size_t _size, int _position) const
{
char* data = new char[_size];
memcpy(data, m_data + _position - _size, _size);
}
void Write(void* _data, size_t _size, int _position)
{
char* data = new char[_size];
memcpy(m_data + _position, data, _size);
return 1;
}
int main()
{
Chunk c(10);
int value = 10, result;
c.Write(&value, sizeof(int), 0);
c.Read(&result, sizeof(int), sizeof(int));
cout << *((int *)result) << endl;
return 0;
}
What am I doing wrong?
"What am I doing wrong?" - Pretty much everything:
To begin with, both Read and Write functions end with a memory leak, as the allocated-memory pointed by the data local variable is "lost" (no one "knows" the address after the function returns).
In addition, what exactly are you expecting to get by casting (int*)result? It is most certainly not going to be a valid memory address which you can then safely dereference using *((int*)result).
In your read function, the parameter _data is not used, so it won't modify anything. It should be:
void Read(void* _data, size_t _size, int _position)
{
memcpy(_data, m_data + _position - _size, _size);
}
Also, the code to output variable result doesn't make sense, should just be:
cout << result << endl;
As the program is not the complete program, I don't know if there're still other errors

Memory leak error?

For a simple assignment to do with dynamic memory and copy constructors, my prof has assigned us a simple assignment, but I get an error during the second time my delete [] happens.
header file:
class Stream {
int len;
char *hold;
char* newmem(int);
public:
Stream ();
Stream (int);
Stream(const char *);
~Stream ( );
void operator=(const Stream &);
Stream(const Stream &);
friend void show(Stream);
void operator<<(const char*);
};
it should be fairly simple. here is my code:
#include <iostream>
#include <new>
#include <cstring>
using namespace std;
#include "stream.h"
char* Stream::newmem(int x) {
char * tmp;
try {
tmp = new char[x];
}
catch(std::bad_alloc) {
tmp = NULL;
}
if(tmp)
cout << "newmem: " << (void *) tmp << endl;
return tmp;
}
Stream::Stream ( ) {
len = 1000;
hold = newmem(len);
if (hold)
strcpy (hold, "");
}
Stream::Stream(int n) {
len = n;
hold = newmem(len);
if (hold)
strcpy (hold,"");
}
Stream::Stream(const char * dat) {
len = strlen(dat) +1;
hold = newmem(len);
if (hold)
strcpy(hold,dat);
}
Stream::Stream(const Stream &from) {
cout << "in the copy constructor, allocating new memory..." << endl;
cout << "original pointer address is: " << (void *) from.hold << endl;
cin.get( );
len=from.len;
hold=newmem(len +1);
cout << "new pointer address is: " << (void *) hold << endl;
cin.get( );
if(hold)
strcpy (hold,from.hold);
}
Stream::~Stream ( ) {
cout << "destruct: " << (void *) hold << endl;
cin.get( );
if (hold)
delete [] hold;
}
void Stream::operator= (const Stream &from) {
if(hold)
delete [ ] hold;
len = from.len;
hold=newmem(len +1);
if (hold)
strcpy(hold,from.hold);
}
void show (Stream prt) {
cout << "String is: " << prt.hold << endl << "Length is: " << prt.len << endl;
}
void Stream::operator<< (const char *data) {
int dlen = strlen(data);
for (int i=0 ; i<=len && i<=dlen ; i++) {
hold[i] = data[i];
}
}
int main( ) {
char data[ ] = "Growing up it all seems so one-sided;"
"Opinions all provided;"
"The future pre-decided;"
"Detached and subdivided;"
"In the mass production zone!"
"-Neil Peart- \"Subdivisions\"";
Stream x1, x2(25), x3;
x1 << data;
x2 << data;
show(x1);
show(x2);
x3 = x2;
show(x3);
return 0;
}
and my output / error:
in the copy constructor, allocating new memory...
original pointer address is: 0x804c008
new pointer address is: 0x804c808
String is: Growing up it all seems so one-sided;Opinions all provided;The future pre-decided;Detached and subdivided;In the mass production zone!-Neil Peart-Subdivisions"
Length is: 1000
destruct: 0x804c808
in the copy constructor, allocating new memory...
original pointer address is: 0x804c3f8
new pointer address is: 0x804c808
String is: Growing up it all seems so
Length is: 25
destruct: 0x804c808
*** glibc detected *** a.out: free(): invalid pointer: 0x0804c808 ***
The for loop in the operator<< has two off-by-one errors:
for (int i=0 ; i<=len
allows i==len, but the only valid indices of hold are 0..(len-1). So, you can write one off the end.
Secondly, as thiton pointed out, it doesn't copy the \0 terminator even if there is space.
A correct implementation might look like:
void Stream::operator<< (const char *data) {
int source_len = strlen(data);
int copy_len = min(source_len, len-1); // allow for terminator
for (int i=0; i<copy_len; i++) {
hold[i] = data[i];
}
hold[copy_len] = '\0';
}
although it'd be better practise to simply use strncpy.
Note that the idiom of using half-open (or one-past-the-end) ranges is standard not only in direct array indexing, but also with C++ iterators. So, you should always expect to see
for (i=0; i<n; ++i) {
or
for (i = begin; i != end; ++i) {
and should generally treat closed-range loops like yours as a smell that warrants further investigation.
First a little self-help advice: The most important tool for catching memory access errors is valgrind. Run it on your program, and you'll get a warning every time you try to access unallocated or uninitialized memory. It's no substitute for knowledge, but the next best thing.
While I get different output than you get, errors seem to interact here:
The operator<< has an off-by-one error in the range check. It writes one byte too much (hold[len]).
operator<< does never write the terminating null byte. Both errors are invoked by x2 << data.
When the copy constructor tries to copy the string from x2, strcpy finds no terminating null byte and both reads right off the end of x2.hold and writes past the end of x3.hold. The latter has the potential for unbounded corruption and probably caused your error.
Whenever you deal with C strings, make very, very sure to get termination right. The fixed version is:
void Stream::operator<< (const char *data) {
int dlen = strlen(data);
hold[len-1] = 0;
for (int i=0 ; i < len-1 && i <= dlen ; i++) {
hold[i] = data[i];
}
}
Or, using the std library:
void Stream::operator<< (const char *data) {
strncpy(hold, data, len);
hold[len-1] = 0;
}

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,

Dynamic Memory Allocation for Dictionary

Hi there I need to Build something like a dictionary and each word according to my code can have 100 meanings, but maybe it has only 5 meanings then I will be allocating 95 extra space for nothing or maybe it has more than 100 meanings then the program will crash, I know the vector class is very easy and could be good use of, but the task is almost building my own vector class, to learn how it works. Thus **meanings and some other stuff remain the same and here is my code, Also I know I am causing memory leakage, how can I delete properly? :
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
class Expression {
char *word_with_several_meanings; // like "bank", "class"
char **meanings; // a pointer to a pointer stores all meanings
int meanings_ctr; // meanings counter
//-----------FUNCTIONS------------------------------------------------
public:
void word( char* = NULL );
void add_meaning(char* = NULL);
char* get_word();
int get_total_number_of_meanings();
char* get_meaning(int meanx = 0);
Expression(int mctr = 0); // CTOR
~Expression(); // DTOR
};
Expression::Expression(int mctr ) {
meanings_ctr = mctr; // Setting the counter to 0
meanings = new char * [100]; // Allocate Space for 100 meanings
}
Expression::~Expression() {
delete [] meanings; // Deleting the memory we allocated
delete [] word_with_several_meanings; // Deleting the memory we allocated
}
void Expression::word( char *p2c )
{
word_with_several_meanings = new char[strlen(p2c)+1];
// copy the string, DEEP copy
strcpy(word_with_several_meanings, p2c);
}
void Expression::add_meaning(char *p2c)
{
//meanings = new char * [meanings_ctr+1];
meanings[meanings_ctr] = new char[strlen(p2c)+1];
strcpy(meanings[meanings_ctr++],p2c);
}
char * Expression::get_meaning( int meanx )
{
return *(meanings+meanx);
}
char * Expression::get_word()
{
return word_with_several_meanings;
}
int Expression::get_total_number_of_meanings()
{
return meanings_ctr;
}
int main(void) {
int i;
Expression expr;
expr.word("bank ");
expr.add_meaning("a place to get money from");
expr.add_meaning("b place to sit");
expr.add_meaning("4 letter word");
expr.add_meaning("Test meaning");
cout << expr.get_word() << endl;
for(int i = 0; i<expr.get_total_number_of_meanings(); i++)
cout << " " << expr.get_meaning(i) << endl;
Expression expr2;
expr2.word("class");
expr2.add_meaning("a school class");
expr2.add_meaning("a classification for a hotel");
expr2.add_meaning("Starts with C");
cout << expr2.get_word() << endl;
for( i = 0; i<expr2.get_total_number_of_meanings(); i++)
cout << " " << expr2.get_meaning(i) << endl;
Expression expr3;
expr3.word("A long test ... ");
char str[] = "Meaning_ ";
for (int kx=0;kx<26;kx++)
{
str[8] = (char) ('A'+kx);
expr3.add_meaning(str);
}
cout << expr3.get_word() << endl;
for(i = 0; i < expr3.get_total_number_of_meanings(); i++)
cout << " " << expr3.get_meaning(i) << endl;
return 0;
}
When you are allocating a multi dimensional array with new then you are allocating it with a loop, e.g.
char **x = new char*[size]
for (int i = 0; i < N; i++) {
x[i] = new int[size];
}
So you also have to delete it in this fashion:
for (int i = 0; i < N; i++) {
delete[] x[i];
}
delete[] x;
Thus when you're having arbitrary sizes of your array you'll have to store them somewhere for using them within the destructor.
delete [] meanings; // Deleting the memory we allocated
won't get rid of your memory allocated, only the pointers themselves.
To free up the actual memory, you will need to iterate through your meanings array, and delete [] each element in it.
Something like:
for (int i = 0; i < meanings_ctr; ++i)
{
delete [] meanings[meanings_ctr];
meanings[meanings_ctr] = NULL;
}
delete [] meanings;
--
For the problem of what to do if you get more than 100 meanings (or in general when your collection is full), the standard technique is to allocate a new array that is double the size (which you can do since it is dynamic), copy your existing collection into that one, and then dispose of your existing one.
I'd use a simple linked list (this is simplified, not complete and untested; also there should be proper getters/setters and stuff):
class Meaning {
char text[20];
Meaning *next;
Meaning(const char *text) : next(0) {
strcpy(this->text, text);
}
}
class Word {
char text[20];
Meaning *first;
Meaning *last;
Word(const char *text) : first(0), last(0) {
strcpy(this->text, text);
}
~Word() {
Meaning *m = first, *n;
while(m) {
n = m->next;
delete m;
m = n;
}
}
void AddMeaning(const char *text) {
if (last) {
last = last->next = new Meaning(text);
}
else {
first = last = new Meaning(text);
}
}
void print() {
printf("%s:\n\t", text);
Meaning *m = first;
while (m) {
printf("%s, ", m->text);
m = m->next;
}
}
}