Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
TASK: Let's say there is an integer stack S with M elements. Give the algorithm that will remove all those numbers from stack S that appear two or more times. (write the task using C/C++)
NOTE: We are not allowed to use std::stack to solve this task.
First of all I decided to use C language, and this is stack implementation I use.
int* stack = (int*)malloc(10 * sizeof(int));
int size = 10;
int sp = -1;
bool isempty() {
return (sp == -1);
}
bool isfull() {
return (sp == size - 1);
}
void push(int x) {
if (isfull()) {
printf("Full!");
}
else {
sp++;
stack[sp] = x;
}
}
int pop() {
int x;
if (isempty()) {
printf("Empty!");
}
else {
x = stack[sp];
sp--;
}
return x;
}
void peek() {
if (!isempty()) {
printf("%d", stack[sp]);
}
}
void clear() {
while (!isempty()) {
pop();
}
}
void print() {
if (!isempty()) {
for (int i = 0; i < sp+1; i++) {
printf("%d ", stack[i]);
}
}
printf("\n");
}
My idea of solving this task was to make another temp stack and copy main stack into it, than use two for loops to compare all elements and inside that I used if statment to check if they are same or not, if they are not same I just pushed them into back into stack that was previously cleared, by this way I'm supposed to skip all duplicate elements but for some reason this code is not working properly it keeps spamming me "Full!" message.
void removeDuplicates() {
int* temp = (int*)malloc(10 * sizeof(int));
int temp_size = 10;
int temp_sp = -1;
for (int i = 0; i < sp + 1; i++) {
temp[i] = stack[i];
}
temp_sp = sp;
clear();
for (int i = 0; i < temp_sp+1; i++) {
for (int j = i + 1; j < temp_sp+1; i++) {
if (!(temp[i] == temp[j])) {
push(temp[i]);
}
}
}
}
This is main function that I used to test out functions:
int main() {
push(1);
push(2);
push(3);
push(4);
push(3);
push(5);
removeDuplicates();
print();
return 0;
}
If there is simpler way to solve this by using C++ (not std::stack), let me know.
this code that is supposed to work for normal array, but not sure if it's right for stack as we might using dynamic memory
Whether your code is correct for stacks is nothing to do with dynamic allocation, and everything to do with the interface of a stack. Do you know what that is? It's absolutely essential to solving your problem, and I don't see any hint that you either know how a stack behaves, or tried to research it.
Here you are, the stack abstract datatype:
preserves last-in first-out order
allows you to push a new element onto the top of the stack
allows you to pop the most recently pushed element (that wasn't already popped) from the top of the stack.
That's everything, and there is no random access (ie, stack[j] will never be a valid expression), so it is obviously impossible for the algorithm you showed to work.
If you don't have a stack implementation already - write one! You're going to need a stack to compile and test your algorithm anyway. The definitions you show describe the storage, but not the interface.
There are only two functions to code (plus the two to create and destroy a stack, and optionally one to query the size).
Now for the algorithm - you can only ever access the top element of a stack, so you need to think about what to with the elements you pop that aren't duplicates. They have to go somewhere, because you can't see below them while they're on your main stack, and you mustn't lose them.
Your edit shows you do have a stack datatype, sort of: it uses three global variables which you have to take care not to break, and you can't reuse any of the functions for your temporary stack, because they operate on those globals.
Even in C, I'd expect to see something like this (untested, un-compiled sample code based on yours above)
struct Stack {
int size;
int sp;
int data[];
};
struct Stack* stack_create(int elements) {
struct Stack *s = malloc(sizeof(*s) + elements * sizeof(int));
s->size = elements;
s->sp = -1;
return s;
}
bool stack_isEmpty(struct Stack *s) { return s->sp == -1; }
bool stack_isFull(struct Stack *s) { return s->sp == s->size - 1; }
void stack_push(struct Stack *s, int x)
{
assert(!stack_isFull(s));
s->data[++s->sp] = x;
}
int stack_pop(struct Stack *s)
{
assert(!stack_isEmpty(s));
return s->data[(s->sp)--];
}
because then you can use the same operations on your main and temporary stacks.
If the removeDuplicates message is supposed to be implemented in terms of the stack abstraction, you need an algorithm you can implement in terms of stack_push, stack_pop etc.
If the removeDuplicates message is supposed to be an internal function operating directly on the stack implementation, rather than being implemented in terms of the stack abstraction - then your basic approach is probably OK (if very far from optimal), and you just need to learn to debug your code.
I still don't know which one of those is true (so I won't vote to re-open yet), but they are completely different questions.
I see a few problems with your current code:
In the loop
for (k = j; k < size; k++)
{
stack[k] = stack[k + 1];
}
you go out of bounds because you use stack[k+1]. How would you fix that?
But then after you have moved all the elements down by 1, the new stack[j] may be another duplicate of stack[i]. How would you fix that? You might consider using a while loop.
You use a global variable size which is the stack size. But there is also a variable sp that is the stack pointer and indicates the part of the stack in use. So instead of looping over size you should loop over sp.
Note what the stack pointer points at: the value -1 means stack empty, so any other value points at the current value at the top of the stack. (This is important beause the other interpretation of the stack pointer is that it points at the next free element of the stack.)
This sp of course decreases with every duplicate you remove from the stack.
Related
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 3 years ago.
Improve this question
Stack create(int c)
{
Stack S=(Stack)malloc(sizeof(struct stack));
S->size=c;
S->top=-1;
S->array=(char *)malloc(sizeof(char)*c);
return S;
}
Stack makeEmpty(void)
{
Stack *S1=create(100);
S1[0]->top=-1;
return S1;
}
char pop(Stack S)
{
return S->array[S->top--];
};
int main(void)
{
Stack *S1;
S1=makeEmpty();
int j;
int k=0;
char result[30];
for(j=0; j<2; j++)
{
char result1=pop(S1);
strcat(result, result1);
k++;
}
}
I skipped some parts, like typedef struct stack Stack;
What I wanted to do was pop out elements from the stack while for-loop works. Then, store those elements in a new array which is result. To check whether it works or not, I printed out but I had a runtime error. How to store the element and how to print it out?
I've made copy&paste of your code, and it doesn't get compiled. I think that
you are either not posting your actually code nor you don't bother to compile and read the compiler warnings. It's rather difficult to help you. Here some things I noticed:
1.
create must return a pointer to Stack, not the object.
Stack *create(int c)
{
Stack *S = malloc(sizeof *S);
S->size=c;
S->top=-1;
S->array = malloc(c);
return S;
}
2.
Same goes for makeEmpty
Stack *makeEmpty(void)
{
Stack *S1=create(100);
S1->top=-1;
return S1;
}
3.
pop should get a pointer to Stack, not the object
char pop(Stack *S)
{
return S->array[S->top--];
};
Here you should check whether there are elements on your stack. int pop(Stack *S, char *val) where it returns 1 and writes on *val on
success, and returns 0 otherwise would be better.
4.
Judging from your pop you are pushing char only. I don't get what you
are trying to do with strcat. Either way, you are doing strcat wrong. You
are declaring a stack with 100 spaces, but you are only declaring 30 spaces
for result. What if you have more than 31 elements on your stack? I know
that you are only inspecting 2 elements but it's easy to overlook that and
expand it to go through all the stack without changing the memory requirements
for result.
Also strcat is a function that works with C-Strings, that means it expects
C-Strings. A C-String must be \0 terminated, yours are not. You have
something that looks like a C-String but it's not. If you insist on using
strcat, the you should do it like this:
for(j=0; j<2; j++)
{
char result1[] = { pop(S1), 0 };
strcat(result, result1);
}
for learning purpose I'm implementing a stack with it's functions in c.
I added some small additional functionality to use malloc the first time and try to understand it properly.
I wrote a function which is initially creating my stack struct. The return value of the function is a new struct with an already allocate memory. What is the best way to handle a malloc exception in a function which return value should be a struct? Maybe should I design the function different? I'm aware that the printf is not doing it's job ;)
My Stack struct:
typedef struct Stack
{
int count;
int capacity;
int *data;
} Stack;
Creating a Stack instance:
Stack create_stack(int initialcapacity)
{
Stack new_stack;
new_stack.count = 0;
new_stack.capacity = initialcapacity;
if (!(new_stack.data = malloc(initialcapacity * sizeof(int))))
printf("not enough memory!");
return new_stack;
}
The function is called with the initial capacity of the stack:
Stack stack = create_stack(10);
A second question came up while I was writing a function to delete the Stack instance.
int delete_stack(Stack *stack)
{
stack->count = 0;
stack->capacity = 0;
free(stack->data);
stack->data = NULL;
return 0;
}
Am I able to remove also the struct instance itself? It feels not complete to just set the values back to 0 and direct int* to NULL.
Last but not least, I have a question to my push function. Also here I added some functionality which allows me to push something on the stack while it is already full:
void push(int value, Stack *stack)
{
if (stack->count == stack->capacity)
{
int *temp = malloc(stack->capacity * sizeof(int));
int i;
for (i = 0; i < stack->count; i++)
temp[i] = stack->data[i];
free(stack->data);
stack->data = NULL;
stack->data = malloc(stack->capacity * 2 * sizeof(int));
for (i; i > -1; i--)
stack->data[i] = temp[i];
free(temp);
temp = NULL;
stack->data[stack->count] = value;
stack->count++;
stack->capacity = stack->capacity * 2;
}
else
{
stack->data[stack->count] = value;
stack->count++;
}
}
Is it necessary to "free" the smaller array and put the pointer to NULL before I allocate a new array double the size?
If there is anything from my code which is unnecessary or not written properly, please let me know, I'm grateful for any hint which makes me better.
Cheeers,
me
I would do it with pointers. That is, your create_stack() would allocate a new Stack struct using malloc, then set the values to the struct and usee malloc again to allocate space for the Stack->data. Like this:
Stack* create_stack(int initialcapacity) {
Stack* new_stack = malloc(sizeof(Stack));
if (new_stack == NULL)
return NULL; // return null to tell the caller that we failed
new_stack->count = 0;
new_stack->capacity = initialcapacity;
new_stack->data = malloc(initialcapacity * sizeof(int))
if (new_stack->data == NULL)
{
free(new_stack);
return NULL;
}
return new_stack;
}
With this, we "handle" a malloc error by returning NULL, so the caller knows we failed.
Now that we have used malloc to allocate the Stack struct, you can (read: MUST) free the space taken by it using free(stack); in delete_stack().
In push(), the temporary array is not needed, that is, you could just right away allocate a bigger array, copy the contents to it from the original stack->data, free stack->data and set it to the newly malloc'd array:
int *temp = malloc(stack->capacity * 2 * sizeof(int));
// TODO: what if malloc fails?
int i;
for (i = 0; i < stack->count; i++)
temp[i] = stack->data[i];
free(stack->data);
stack->data = temp;
stack->data[stack->count] = value;
stack->count++;
stack->capacity = stack->capacity * 2;
Q. What is the best way to handle a malloc exception in a function which return value should be a struct?
There are at least three ways:
1) Instead of returning structure itself, return a pointer to it. This means two mallocs: one is for structure itself and another one is for data field. Returning NULL pointer means that something went wrong during construction.
struct Stack* create_stack(int initialcapacity) {
struct Stack* stack = malloc(sizeof(struct Stack));
...
return stack;
}
2) More flexible way is to pass pointer to already allocated structure. Flexibility comes from idea that calling code controls where to allocate structure: on stack or in dynamic memory. Return value of function may be used solely to notify calling code about errors:
bool create_stack(int initialcapacity, struct Stack* stack) {
...
}
// if calling code wants structure on stack (yeah, "stack" on stack)
struct Stack stack;
if (!create_stack(50, &stack)) {
die();
}
// if calling code wants it in dynamic memory
struct Stack* stack = malloc(sizeof(struct Stack));
if (!stack) {
die();
}
if (!create_stack(50, stack)) {
die();
}
3) If your program is not a 10,000+ LOC production code, easiest way may be to simply print error message and abort program immediately if allocation fails. Usually allocation errors are fatal: you can't recover in any meaningful way if there is not enough memory. You may even create a wrapper function over malloc to automatically catch such errors and exit:
void* my_malloc(size_t count) {
void* ptr = malloc(count);
if (ptr == NULL) {
fprintf(stderr, "Allocation failed");
exit(EXIT_FAILURE);
}
return ptr;
}
Q. Am I able to remove also the struct instance itself?
No, you can't. Because it is allocated on stack (the structure itself, not the data). If you want to delete structure itself, you need to use approach #1 from above.
And, by the way, there is no need to set zeroes and NULLs to fields. It doesn't delete anything. Such approach is used rarely and with only purpose to catch bugs (when calling code first deletes some structure and then tries to use it afterwards).
Q. Is it necessary to "free" the smaller array and put the pointer to NULL before I allocate a new array double the size?
Once again, you don't need to NULLify anything -- it doesn't delete anything. Instead of two mallocs and manual copying use realloc, which will do most of the work for you.
Generally, you should be able to declare a structure, then have an array of say 64 of them, with an integer to say which entry is on the top. Very simple, and no dynamic allocation. But 64 is pretty low, That's because stacks, recursion, and levels of nesting are intimately linked. Usually it should be possible to see that 64 is an insane level of nesting, and no legitimate input will ever even approach it. You then might need a guard to protect from malicious or corrupted input, but that just terminates the program or sub-routine.
If you can't establish a low sanity bound on a stack, it might that you still need one. Either it's a rare case where nesting goes very deep, or it's that you haven't approached the problem in the best way, but a sub-optimal program that still works is better than no program.
So you use the same structure, but the stack is set up with a call to
malloc() and, if it grows out of bounds, regrow with a call to realloc().
You might want to still sanity check it, but now sanity checks are
much higher, a million or so as opposed to 64. You also have to check that
realloc does not fail.
typedef struct
{
int x;
char astring[32];
} ENTRY;
static ENTRY *stack = 0;;
static int top = -1;
static int N = 0;
void push(const ENTRY *e)
{
/* grow logic like this */
ENTRY *temp = realloc(stack, newsize * sizeof(ENTRY));
if(temp)
stack = temp;
else
{
/* reallocation has failed but stack still valid */
free(stack);
N = 0;
top = -1;
/* for the sake of argument do this. We need temp to avoid
a memory leak */
fprintf(stderr, "out of memory\n");
}
/* push here, trivial */
}
int pop(ENTRY *e)
{
/* e is a non-const pointer. Fill and reset stack top */
}
You might want the stack global as in the example or you might want to
wrap it in a structure you pass about. Usually you'll want either pointers
or structures on the stack, but occasionally you might need a stack
of integers or floating point values.
There's no good way of handling memory allocation errors in C, especially
ones which can't happen (a computer with several GB of memory installed
is more likely to develop an electrical fault than to run out
of memory when asked for a couple of kilobytes). The usual rule is to
shunt up. But that makes the push call difficult, because every push
could potentially run the computer out of memory (but it can't really,
it's just your encapsulation allows the function to fail).
For example, take this example functions:
#include <stdlib.h>
#define MAX 100
typedef struct stack {
int sp;
int val [MAX];
} STACK;
void initStack (STACK *s){
s->sp = 0;
}
int push (STACK *s, int x){
if(s->sp == MAX) return -1;
else s->val[s->sp++] = x;
return 0;
}
int main(){
STACK s;
int pushval, p;
initStack(&s);
p = push(&s, 1);
pushval = s.val[s.sp-1];
printf("pushval %d\n", pushval);
return 0;
}
So in this case if I do s.val[s.sp] I get gibberish. If I do s.val[s.sp-1] I get the value I pushed on to the stack. I don't know if the stack pointer should point to the "next available space" aka be equal to the number of elements in the array, or should be equal to the index of the last element of the array aka number of elements in the array - 1
This is just a matter of convention. Many implementations let the top stack pointer points to the "next available space", but you can really do what you prefer, provided that externally your stack behave as intented.
For me, the most natural implementation of an array-based stack is one that grows "downwards", with the stack pointer pointing to the most recently pushed element:
void initStack (STACK *s)
{
s->sp = MAX;
}
int push (STACK *s, int x)
{
if( !s->sp )
return 0;
else
s->val[--s->sp] = x;
return 1;
}
int pop(STACK *s, int *x)
{
if ( s->sp == MAX )
return 0;
else
*x = s->val[s->sp++];
return 1;
}
The checks are simpler IMO, and since it never decrements below 0, you can safely use an unsigned type as your stack pointer (which I tend to do for reasons that probably aren't completely rational).
Note that this mimics the x86 (and many other architectures') stack behavior, in that the SP grows "downwards", towards 0.
Notice that I changed the return value on success and failure, since in C 0 means "false" and non-zero means "true". This way you can write code like
if ( push( stack, val ) )
{
...
}
else
{
// push failed, handle as appropriate
}
Again, this is just a more natural implementation IMO.
EDIT
One big drawback of this method is that it's difficult to grow the stack if necessary. If you allocate the backing array dynamically, you can use realloc to extend it, but you will have to move all the existing data to the new stack "bottom", which would be expensive and a pain in the ass. By contrast, if you grow the stack upwards, you don't have that problem. But, if I wanted a stack that could grow or shrink as necessary, I wouldn't use an array-based stack, I'd use one based on a linked list, where items are pushed by adding them to the head of the list and popped by removing them from the head.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 7 years ago.
Improve this question
So, this is working fine... that means, no compiler errors, it seems that there is no memory leak and it is doing what I wanted it to do. That said should it be working? When I go to books_init I send a local variable to collection, doesn't it mean that when I go back to main it shouldn't be working? (or undefined behavior?). Also, in case you say that I have to malloc it, do I have to free it after? (commented on cleanup)
/* pseudo struct Collection{
size_t size, capacity;
Volume *volumes;
} */
void collection_init(Collection *col, size_t capacity){
col->size = 0;
col->capacity = capacity;
col->volumes = malloc(sizeof(Volume) * capacity);
}
void collection_resize(Collection *col, size_t capacity){
Volume *v = realloc(col->volumes, capacity * sizeof(Volume));
if(!v) return;
col->capacity = capacity;
col->volumes = v;
}
void collection_add(Collection *col, Volume *volume){
if(col->size >= col->capacity)
collection_resize(col, col->capacity * 2);
col->volumes[col->size++] = *volume;
}
void collection_clean(Collection *col){
//for(vol : col->vol) free(vol);
//should I free every element or just volumes?
free(col->volumes);
}
void books_init(Collection *col){
for(int i = 0; i < 25; ++i){
Volume v = {.swag = i};
collection_add(col, &v);
}
}
int main(){
Collection col;
collection_init(&col, 10);
books_init(&col);
for(int i = 0; i < col.size; ++i){
printf("\tVol[%d].id = %d\n", i, col.volumes[i].swag);
}
collection_clean(&col);
return 0;
}
Thanks for your time
This line in books_init
Volume v = {.swag = i};
creates a local variable called v with member swag initialized to i. The address of that variable is then passed to collection_add. That is allowed because v is still in scope.
This line in collection_add
col->volumes[col->size++] = *volume;
makes a copy of the contents of the Volume structure, and stores that copy in the memory that was allocated in collection_init.
After collection_add returns, the variable v in books_init goes out of scope, but that's OK because the contents of v were copied and saved in the memory that col->volumes points to.
When the program ends, collection_clean only needs
free(col->volumes);
to remove all of the Volume copies from memory.
The only flaw I see in your program occurs if realloc fails. In that case, you still write to the Volume array. This will cause a buffer overrun and memory corruption. To avoid this, the collection_add function should verify that the collection_resize function succeeded before performing the copy. For example, you could check again that col->capacity > col->size before doing the copy.
TL;DR your code is fine as long as the realloc always succeeds.
I have this problem in C where I have to implement a garbage collector. I'm stuck on the fact that I was given 4 functions to complete and not sure how they connect to one another. I'm not sure what to do. This is what I have so far:
void mygc() {
//int **max = (int **) 0xbfffffffUL; // the address of the top of the stack
unsigned long stack_bottom;
int **max = (int **) GC_init(); // get the address of the bottom of the stack
int* q;
int **p = &q; // the address of the bottom of the stack
while (p < max) {
//printf("0. p: %u, *p: %u max: %u\n",p,*p,max);
mark(*p);
p++;
}
//utilize sweep and coalesce (coalesce function already written)
}
void mark(int *p) {
int i;
int *ptr;
//code here
}
void sweep(int *ptr) {
// code here
}
int *isPtr(int *p) {
//return the pointer or NULL
int *ptr = start;
//code here
}
If you don't even understand the question perhaps it's best to speak to your teaching staff. To get you started here's the general idea.
mygc is obviously the top level function that does the GC.
mark is called to mark memory location/object as in use. It also needs to mark all memory referenced by that location/object as in use (recursive).
sweep is called to unmark all the previously marked memory and to claim back (garbage collect) those locations that are not marked.
isPtr is called to determine whether a memory location is a pointer (as opposed to being any other data). This is used by mark to know whether a memory location needs to be marked or not.
So putting that all together the general pseudo code is:
mygc()
{
loc_list = get stack extents and global variables
foreach (p in loc_list) {
if (isPtr(p)) {
mark(p)
}
}
foreach (p in heap) {
sweep(p)
}
}
There are obviously lots of details not dealt with in that psuedo code. But it should hopefully be enough to answer your original question which is how the four functions fit together.