I am writing the program for Generic Stack.SO I pass the function pointer to the function StackNew() API. When I see the address of the StringFree API, it is 0x012b2770 ,
but when I see the address of (*free) API it is 0x012B13ED
I had thought that the pointer's copy will be passed . As you can see that's not happening but the program is working as it should .
I thought that the starting address of the StringFree API is passed ,like suppose the starting address of StringFree is 0x10 then , 0x10 is passed to free API so that the free also points to starting address of StringFree so that the value of the free also will be 0x10 ,but that is not happening .Can you explain me what is going on here? Thanks.
My program :
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string.h>
#include<iostream>
using namespace std;
typedef struct
{
void *elems;
int loglen;
int alloclen;
int elemSize;
void (*freefn) (void*);
}Stack;
void StringFree(void* target)
{
char** s = (char**)target;
free(*s);
if (s != NULL) {
std::cout << "Not null" << std::endl;
}
s = NULL;
}
void StackNew(Stack *s, int elemSize,void (*free) (void*))
{
s->elemSize = elemSize;
s->loglen = 0;
s->alloclen = 4;
s->elems = malloc(4 * elemSize);
s->freefn = free;
//assert(s->elems != 0 );
}
void StackDispose(Stack *s)
{
if (s->freefn != 0)
{
for (int i = 0 ; i < 3 ; i++ )
{
void* source = (char*)s->elems + i*s->elemSize;
s->freefn(source);
}
}
}
void StackPush(Stack *s, void* elemAddr)
{
if (s->alloclen == s->loglen)
{
s->alloclen *= 2;
s->elems = realloc(s->elems, s->alloclen * s->elemSize);
}
void* target = (char*)s->elems + s->loglen*s->elemSize;
memcpy(target, elemAddr, s->elemSize);
s->loglen++;
}
void* StackPop(Stack *s, void* elemAddr)
{
s->loglen--;
void* source = (char*)s->elems + s->loglen * s->elemSize;
memcpy(elemAddr, source, s->elemSize);
return elemAddr;
}
int main()
{
Stack s;
std::cout << sizeof(s.freefn) << std::endl;
const char* friends[] = { "AlexJonesisabitchofjoerogan" , "Bob" , "Carl"};
StackNew(&s, sizeof(char*),StringFree);
for (int i = 0; i < 3; i++)
{
//int* cc = (int *)_strdup(friends[i]);
char* copy = _strdup(friends[i]);
std::cout << copy << std:: endl;
StackPush(&s, ©);
}
char* name;
for (int i = 0; i < 3; i++)
{
StackPop(&s, &name);
printf("%s\n", name);
// free()
}
StackDispose(&s);
std::cin.get();
return 0;
}
Pointers are still passed by value, so when you pass a pointer, it copies the value of the pointer as it would for an integer.
Related
I've been writing an VM/Interpreter combination thingy, I don't know how to exactly describe it.
Everything behaved as it should, now before I have hundreds of lines of code, I wanted to go into Garba Collection, because there were some pointers which somehow got lost, in some way. Not that I didn't delete pointers, I created, but they somehow got lost in the proccess of interpreting/running the code.
So, I wanted to track them. I wrote my own "Memory Manager" in some way, it's just a std::vector, where I collect all pointers in.
To track and allocate pointers, I have following code:
struct MemBlock {
bool free;
void* ptr;
size_t size;
};
std::vector<MemBlock*> mem;
size_t max_size;
size_t mem_size;
int count = 0;
void mem_init(size_t maxSize) {
max_size = size/sizeof(MemBlock*);
}
void* mem_alloc(size_t size) {
for (int i = 0; i < count; i++) {
MemBlock* block = mem[i];
if (block->free) {
mem_size -= block->size;
mem_size += size;
block->free = false;
block->ptr = malloc(size);
block->size = size;
if (block->ptr == nullptr) {
throw std::exception();
}
return block->ptr;
}
}
void* ptr = malloc(sizeof(size));
if (ptr == nullptr) {
throw PointerNullException();
}
MemBlock* block = (MemBlock*) malloc(sizeof(MemBlock));
*block = (MemBlock) {
false,
ptr,
size
};
mem_size += size;
count++;
mem.push_back(block);
return block->ptr;
}
But as soon, as I use mem_alloc() and initialize the object inside of the pointer:
Int* i = (Int*) mem_alloc(sizeof(Int));
*i = (Int) {}; // -- Here
i->value = atoi(advance().c_str());
The GCC AdressSanitizer shows following error:
==5939==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000098 at pc 0x555963d82fc5 bp 0x7fff4ec39070 sp 0x7fff4ec39060
WRITE of size 4 at 0x602000000098 thread T0
If I remove said line, then it just occurs on the nex line. The the pointer does point to a valid memory location, if not it should've had thrown an exception.
I'm sure that I missed something/did something wrong, of course.
But I don't know what. This is how I learned it, or at least what I understood...
Edit:
This would be a minimal reproducible Example:
#include <iostream>
#include <stdlib.h>
#include <vector>
struct Object {
const char* type;
};
template <typename T>
struct Primitive : Object {
T value;
};
struct Int : Primitive<int> {
const char* type = "int";
};
struct MemBlock {
bool free;
void* ptr;
size_t size;
};
std::vector<MemBlock*> mem;
size_t mem_size = 0;
int count = 0;
void* mem_alloc(size_t size) {
for (int i = 0; i < count; i++) {
MemBlock* block = mem[i];
if (block->free) {
mem_size -= block->size;
mem_size += size;
block->free = false;
block->ptr = malloc(size);
block->size = size;
if (block->ptr == nullptr) {
throw std::exception();
}
return block->ptr;
}
}
void* ptr = malloc(sizeof(size));
MemBlock* block = (MemBlock*) malloc(sizeof(MemBlock));
*block = (MemBlock) {
false,
ptr,
size
};
mem_size += size;
count++;
mem.push_back(block);
std::cout << "HI" << std::endl;
return block->ptr;
}
void mem_free(void* ptr) {
for (int i = 0; i < count; i++) {
MemBlock* block = mem[i];
if (block->ptr == ptr) {
free(ptr);
mem_size -= block->size;
block->size = 0;
block->ptr = nullptr;
block->free = true;
}
}
}
int main() {
// Create new Integer-Object
Int* i = (Int*) mem_alloc(sizeof(Int));
std::cout << "[Pointer]: " << i << std::endl;
*i = (Int) {};
i->value = 5;
std::cout << "[Value]: " << i->value << std::endl;
}
Well, thanks to Retired Ninja and Richar Critten, I've got the solution.
In mem_alloc() I've used sizeof(size) to allocate memory to the pointer, which of course is wrong. I guess my head was pretty much off after hours of coding.
But I guess this problem is now solved.
Here is my code
int main(int argc, char *argv[]) {
char const *strings[10] = {"dhh", "aci", "cdh"};
join_def(strings, 'l');
return EXIT_SUCCESS;
}
// part 1 read lines
void join_def(char const **strings, char delim) {
char *t = new char[100];
//int length = 0;
t[0] = '\0';
int x = sizeof(strings);
std::cout << delim << std::endl;
for (int i = 0; i < x; i++) {
int size = 0;
while(strings[i][size]!='\0'){
size++;
std::cout << strings[i][size] << std::endl;
}
}
}
I have spent hours now I just can't get to concatenate it
For this task, I cannot use cstring or anything other than iostream so please don't suggest.
The output needs to be a c-string = "dhhlacilcdh"
First, you cannot determine the number of elements in an array passed to a function, as that array will decay to a simple pointer. So, your sizeof(strings) expression will evaluate (at compile time) to the (fixed) size, in bytes, of a pointer. For the function to be 'aware' of how many elements there are in an array, it needs to be explicitly told (by way of an extra argument).
Second, you have your i' and size indexes the wrong way round in the std::cout << strings[i][size] << std::endl; line and, further, you increment size before printing the relevant character, whereas it should be incremented after you've printed it.
The code below also does the actual concatenation of the strings, and the modified join_def function now returns a pointer to that result (which must be freed when you're finished with it);
#include <iostream>
char* join_def(char const** strings, char delim, int x)
{
char* t = new char[100];
int length = 0;
t[0] = '\0';
//int x = sizeof(strings);
std::cout << delim << std::endl;
for (int i = 0; i < x; i++) {
int size = 0;
while (strings[i][size] != '\0') {
std::cout << strings[i][size] << std::endl;
t[length++] = strings[i][size]; // Append this character
size++;
}
t[length++] = delim; // Append delimiter
}
t[length] = '\0'; // Append nul-terminator
return t;
}
int main()
{
char const* strings[10] = { "dhh", "aci", "cdh" };
char* result = join_def(strings, 'l', 3);
std::cout << result << std::endl;
free(result);
return 0;
}
Note, also, that I have moved the join_def function code to before the main (which calls it). If you don't do this, then will at least have to provide a (forward) declaration of that function before main (just a char* join_def(char const** strings, char delim, int x); on its own will do).
Feel free to ask for further clarification and/or explanation.
I'm not exactly sure what you're trying to do, but maybe this helps?
#include <iostream>
// part 1 read lines
void join_def(char const **strings, char delim)
{
char *t = new char[100];
//int length = 0;
t[0] = '\0';
int x = 0;
for (int i = 0; strings[i] != nullptr; i++)
x += sizeof(strings[i]) - 1;
std::cout << delim << std::endl;
for (int i = 0; strings[i] != nullptr; i++)
{
int size = 0;
while (strings[i][size] != '\0')
{
size++;
std::cout << strings[i][size] << std::endl;
}
}
}
int main(int argc, char *argv[])
{
char const *strings[] = {"dhh", "aci", "cdh", nullptr};
join_def(strings, 'l');
return EXIT_SUCCESS;
}
this is what you are looking for?
look that I remove all the std::endl because it like '\n'
also i moved your size++ after the std::cout
#include <iostream>
// part 1 read lines
void join_def(char const **strings, char delim,int length) {
char *t = new char[100];
//int length = 0;
t[0] = '\0';
int x = length;
for (int i = 0; i < x; i++) {
int size = 0;
while(strings[i][size]!='\0'){
std::cout << strings[i][size]; //<--print befure increment size
size++;
}
std::cout << delim;
}
}
int main(int argc, char *argv[]) {
char const *strings[] = {"dhh", "aci", "cdh"};
join_def(strings,'|',3); //<- need to send the length of the char* array
return EXIT_SUCCESS;
}
I have a class foo like this:
class foo
{
private:
int* a;
public:
foo()
{
a = new int[4];
cout << "a" << endl;
}
};
When I create new object named foo1 and then I debug, after the allocating line, it yields the result: a 0x005a4580 {-842150451}.
But when I replace all int-s by char-s in class definition, it yields an undesired result:
a 0x005694a0 "ÍÍÍÍýýýý\x6ŒÒ•\x5Ÿ"
that the size of a is now greater than 4.
I dont know what happened. Could you please give me an explanation?
Full code:
#include <iostream>
#include <string>
using namespace std;
class String
{
public:
String(char* data)
{
setSize(0);
while (*(data + size) != '\0')
size++;
this->data = new char[size];
//need to allocate memory for 'data' pointer because 'data' pointer is now on the stack and the data must be on the heap
memcpy(this->data, data, size * sizeof(char));
}
void operator=(String rhs)
{
if (this->data != NULL)
delete[] this->data, data = NULL;
this->data = new char[rhs.getSize()]; //allocate
memcpy(this->data, data, size * sizeof(char));
}
int getSize()
{
setSize(0);
while (*(data + size))
size++;
return size;
}
void setSize(int size)
{
this->size = size;
}
void display()
{
for (int i = 0; i < size; i++)
cout << *(data + i);
}
~String()
{
if (data != NULL)
delete[] data, data = NULL;
}
private:
char* data;
int size;
};
void main()
{
String a("abcd");
String b("1");
a.display();
cout << endl;
cout << b.getSize() << endl;
a = b;
cout << a.getSize() << endl;
system("pause");
}
Whatever you're using to look at a doesn't know how much you allocated. It just knows the type.
In the first version it sees int *, so it shows a single int.
In the second version it sees char *, so it assumes it's a C string and prints whatever is in memory up to the first '\0' byte.
The cplusplus.com documentation on getenv() states...
The pointer returned points to an internal memory block, whose content or validity may be altered by further calls to getenv
...which I take to mean, "If you want to keep the content, copy it." So, since I need to retrieve several variables, I wrote a couple of little wrapper functions:
#include <iostream>
#include <string.h>
using namespace std;
void getEnv (char *val, const char *var) {
val = nullptr;
char *enVar = getenv(var);
if (enVar != nullptr) {
val = new char[strlen(enVar) + 1];
strcpy(val, enVar);
}
}
void getEnv (int &val, const char *var) {
val = -1;
char *enVar = getenv(var);
if (enVar != nullptr) {
val = atoi(enVar);
}
}
int main() {
char *textMode = nullptr;
int cLen = 0;
getEnv(cLen, "CONTENT_LENGTH");
cout << cLen << endl << endl;
getEnv(textMode, "TEXT_MODE");
if (textMode == nullptr)
cout << "Not set.";
else
cout << "[" << textMode << "]<br>\n";
return 0;
}
The int version works as expected, but I get nothing back from the char version, and I mean nothing: if I don't initialize *textMode at declaration it remains an uninitialized pointer.
It's pointers, right? Right? I know it is. Gotta be pointers. I'll figure them out one of these days, but hey -- at least I got my linked list to work! Yay!
Your second function takes val (an int) by reference: void getEnv (int &val, const char *var) and so can modify the variable passed to it as you expect.
Your first function takes val (a char*) by value: void getEnv (char *val, const char *var) so modifying val has no affect on the variable passed to it. A simple solution is to simply take it as a reference as well: void getEnv (char *&val, const char *var)
Follow up to my comments and the OP's response to them.
Here's what I was thinking:
#include <iostream>
#include <string.h>
using namespace std;
// Use a class to encapsulate the data need to be captured
// in an environment variable.
class EnvironmentVariable
{
public:
EnvironmentVariable(char const* name) : name_(name), isSet_(false)
{
char *val = getenv(name);
if ( val != nullptr )
{
isSet_ = true;
this->value_ = val;
}
}
bool isSet() const
{
return isSet_;
}
void getValue(char const*& val) const
{
if ( isSet_ )
{
val = this->value_.c_str();
}
else
{
val = nullptr;
}
}
void getValue(int& val) const
{
if ( isSet_ )
{
val = stoi(this->value_);
}
else
{
val = 0; // Find a suitable default value
}
}
private:
std::string name_;
std::string value_;
bool isSet_;
};
int main() {
char const* textMode = nullptr;
int cLen = 0;
EnvironmentVariable env1("CONTENT_LENGTH");
env1.getValue(cLen);
cout << cLen << endl << endl;
EnvironmentVariable env2("TEXT_MODE");
env2.getValue(textMode);
if (textMode == nullptr)
cout << "Not set.\n";
else
cout << "[" << textMode << "]<br>\n";
return 0;
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
Here is the function in question:
#include <cstdlib>
#include <string>
#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include "Train.h"
#include "Platform.h"
const int NUM_TRAINS = 4;
const int NUM_NORTHERNLY_TRAINS = NUM_TRAINS / 2;
const int NUM_SOUTHERNLY_TRAINS = NUM_TRAINS - NUM_NORTHERNLY_TRAINS;
const int NUM_LOOPS = 16;
const char* TRAIN_NAME_ARRAY[NUM_TRAINS]
= { "Thomas the Tank-Engine",
"Percy the Small Engine",
"California Zephyr",
"Tokaido Shinkansen"
};
const int TRAIN_TRANSIT_TIME_MSECS[NUM_TRAINS]
= { 10000, // Thomas
10000, // Percy
5000, // CA Zephyr
1000 // Bullet train
};
Platform northBoundPlatform("North-bound Platform");
Platform southBoundPlatform("South-bound Platform");
void* initiallyNorthernly (void* vPtr)
{
Train* id = ((Train*)vPtr);
for (int i = 0; i < NUM_LOOPS; i++)
{
northBoundPlatform.arrive(id);
northBoundPlatform.leave();
pause();
southBoundPlatform.arrive(id);
southBoundPlatform.leave();
pause();
}
return((void*)id);
}
void* initiallySouthernly (void* vPtr)
{
Train* id = (Train*)vPtr;
for (int i = 0; i < NUM_LOOPS; i++)
{
southBoundPlatform.arrive(id);
southBoundPlatform.leave();
pause();
northBoundPlatform.arrive(id);
northBoundPlatform.leave();
pause();
}
return((void*)id);
}
int main ()
{
pthread_t tidArray[NUM_TRAINS];
Train* trainArray[NUM_TRAINS];
pthread_t tidArray2[NUM_NORTHERNLY_TRAINS];
Train* trainArray2[NUM_NORTHERNLY_TRAINS];
pthread_t tidArray3[NUM_SOUTHERNLY_TRAINS];
Train* trainArray3[NUM_SOUTHERNLY_TRAINS];
for (int i = 0; i < NUM_TRAINS; i++)
{ trainArray[i] = new Train(TRAIN_NAME_ARRAY[i],TRAIN_TRANSIT_TIME_MSECS[i]);
}
int trainInd = 0;
for (int i = 0; i < NUM_NORTHERNLY_TRAINS; i++)
{
pthread_create(&tidArray2[i], NULL, initiallyNorthernly,&trainArray2[i]);
}
for (int i = 0; i < NUM_SOUTHERNLY_TRAINS; i++)
{
pthread_create(&tidArray3[i], NULL, initiallySouthernly,&trainArray3[i]);
}
for (int i = 0; i < NUM_TRAINS; i++)
{
trainArray[i] = NULL;
// Wait for all Train threads. Also, get the pointers to the Train objects
// and delete() them because they were created by 'new'
pthread_join(tidArray[i], (void**)&trainInd);
pthread_join(tidArray2[i],(void**)&trainInd);
pthread_join(tidArray3[i],(void**)&trainInd);
}
return(EXIT_SUCCESS);
}
Here are the appropriate header files:
Train.h
class Train
{
std::string name_;
int pauseTimeUsecs_;
public :
Train (const std::string& newName,
int newPauseTimeUsecs
)
{
name_ = newName;
pauseTimeUsecs_ = newPauseTimeUsecs;
std::cout << getName() << " leaving the trainyard.\n";
}
~Train ()
{
std::cout << getName() << " going back to the trainyard\n";
}
const std::string&
getName ()
const
{ return(name_); }
void pause ()
const
{
usleep(pauseTimeUsecs_);
}
};
Platform.h
class Platform
{
std::string name_;
Train* trainPtr_;
pthread_mutex_t mutexLock_;
pthread_cond_t notEmptyCond_;
pthread_cond_t notFullCond_;
public :
Platform (const std::string& newName
)
{
name_ = newName;
trainPtr_ = NULL;
pthread_mutex_init(&mutexLock_,NULL);
pthread_cond_init(¬EmptyCond_,NULL);
pthread_cond_init(¬FullCond_,NULL);
}
// PURPOSE: To release resources. No parameters. No return value.
~Platform ()
{
pthread_mutex_destroy(&mutexLock_);
pthread_cond_destroy(¬EmptyCond_);
pthread_cond_destroy(¬FullCond_);
}
const std::string&
getName ()
const
{
return(name_);
}
Train* getTrainPtr
()
const
{
return(trainPtr_);
}
void arrive (Train* newTrainPtr
)
{
pthread_mutex_lock(&mutexLock_);
while (getTrainPtr() != NULL)
{
std::cout << getTrainPtr()->getName()
<< " is at " << getName()
<< ", " << newTrainPtr->getName()
<< " must wait.\n";
usleep(10) + rand() % 10;
pthread_cond_wait(¬FullCond_,&mutexLock_);
}
std::cout << newTrainPtr->getName() << " arriving at " << getName() << "\n";
trainPtr_ = newTrainPtr;
usleep(10 + rand() % 10);
pthread_mutex_unlock(&mutexLock_);
pthread_cond_signal(¬EmptyCond_);
}
Train* leave ()
{
pthread_mutex_lock(&mutexLock_);
while (getTrainPtr() == NULL)
{
std::cout << "No train at " << getName() << "!\n";
usleep(10 + rand() % 10);
pthread_cond_wait(¬EmptyCond_,&mutexLock_);
}
Train* toReturn = getTrainPtr();
std::cout << toReturn->getName() << " leaving " << getName() << "\n";
usleep(10 + rand() % 10);
trainPtr_ = NULL;
pthread_cond_signal(¬FullCond_);
pthread_mutex_unlock(&mutexLock_);
return(toReturn);
}
};
After running with gdb, the segmentation fault is occurring when I call arrive on northBoundPlatform(a Platform object). The goal of the function is to make the train object that is pointed to by vPtr arrive() at northernPlatform, leave() at northernPlatform, pause() on the train object, arrive() at the southBoundPlatform, leave() the southBoundPlatform, pause() on the object again, and finally return a pointer to the train that was used.
I am not sure if I am casting vPtr into a Train* correctly which is causing a segmentation fault. I can provide the rest of the main code if necessary. Any help is appreciated.
Your main() function has two for loops for each of NUM_NORTHERNLY_TRAINS, using initiallyNorthernly and initiallySouthernly, but the second loop should be looping with NUM_SOUTHERNLY_TRAINS instead.