I'm trying to get the hang of c and I can't figure out why this code is producing a segfault.
// In src/test.c
#include <stdio.h>
typedef struct {
int length;
int *arr[1000];
} Stack;
void push(Stack *stack, int el) {
(*stack->arr)[stack->length++] = el;
}
int pop(Stack *stack) {
return (*stack->arr)[--stack->length];
}
int main(int argc, char* argv[]) {
Stack stack;
push(&stack, 5);
printf("%d\n", pop(&stack));
return 0;
}
Then I compile and run:
$ gcc src/test.c -o test && ./test
[1] 79484 segmentation fault ./test
You have a few problems.
Like others have mentioned, your int length struct member is never set to zero and thus could contain anything.
You must set the length to 0.
Second, int *arr[1000] is an array of integer pointers. So simply assigning an int to a particular array position is wrong.
You want something more like this:
// In src/test.c
#include <stdio.h>
typedef struct {
int length;
int arr[1000]; // Code change (create an array of integers)
} Stack;
void push(Stack *stack, int el) {
stack->arr[stack->length++] = el; // Code change (no need for additional
// structure member dereference).
}
int pop(Stack *stack) {
return stack->arr[--stack->length]; // Code change (no need for additional
// structure member dereference).
}
int main(int argc, char* argv[]) {
Stack stack;
stack.length = 0; // Code change (set the starting length value to 0)
push(&stack, 5);
printf("%d\n", pop(&stack));
return 0;
}
In your structure, "length" is never initialized, so it contains garbage. WHen you then reference:
(*stack->arr)[stack->length++]
it is indexing memory at an undefined location. So, you need some function, like "init_stack()" to initialize the structs data members to well known values (like zero).
The type of the array in the structure is wrong; it should be int arr[1000];.
As written, you're using uninitialized variables all over the place; neither the length nor any of the pointers in your arr are set to anything reliable (though the pointers should be plain int anyway). Because you have pointers instead of int in your stack, you have a very complex expression to access the stack (the (*stack->arr)[stack->length++], etc), which should be much simpler, as in this rewritten code below.
#include <stdio.h>
typedef struct
{
int length;
int arr[1000];
} Stack;
void push(Stack *stack, int el)
{
stack->arr[stack->length++] = el;
}
int pop(Stack *stack)
{
return stack->arr[--stack->length];
}
int main(void)
{
Stack stack = { 0, { 0 } };
push(&stack, 5);
printf("%d\n", pop(&stack));
return 0;
}
#include <stdio.h>
typedef struct {
int length;
int arr[1000];
} Stack;
void push(Stack *stack, int el) {
(stack->arr)[stack->length++] = el;
}
int pop(Stack *stack) {
return (stack->arr)[--stack->length];
}
int main(int argc, char* argv[]) {
Stack stack;
memset(&stack,0,sizeof(Stack));
push(&stack, 5);
printf("%d\n", pop(&stack));
return 0;
}
The thumb rule is allocate memory before accessing it.
Related
I was given this code from Uni and I am trying to do operations with it , the push function ask for two pointers and I could not figure out how can I pass the data to the item part.I have tried using another structure containing the data but I failed. I am stuck at the end of the code and I would like to learn how to push data using this code. How can I proceed ?
It would be preferable if the data itself was stored in a structur.
Thanks in advance.
typedef struct stk
{
struct stk* elems[MAX]; int top;
} stack, *stackptr;
void Init(stack* s)
{
s->top = 0;
}
int IsEmpty(stack s)
{
return (s.top == 0);
}
void Push(struct stk* item, stack* s)
{
if (s->top == MAX)
printf("Stack voll!");
s->elems[s->top] = item;
s->top++;
}
struct stk* Pop(stack* s)
{
if (IsEmpty(*s)) return NULL;
s->top--;
return s->elems[s->top];
}
int main()
{
stack* ptr = (stackptr)malloc(sizeof(stack));
Init(ptr);
printf("%d\n", ptr->top); // Ist 0 , OK
}
Here is a working stack implementation that store ints. This will afford you the opportunity to test that the operations work as expected. If you really want to store stack * replace the type. It seems unnecessarily confusing for a entry level class to have an assignment of storing pointers to the same thing you are building.
When you deal with pointers you want to make sure the object they point to outline the pointer. You may also want to think of shallow and deep copies with pointers. If you Pop followed by a Push the pointer that was returned from Pop now will point to the new value which would be surprising. Consider a different designs:
Pass in a reference to a variable (aka out parameter) so Pop(stack *s, *v) (and use an enum or define constants for error values).
return a value instead of a pointer; error would not be an out parameter.
return a pointer to a copy of the value and require client to free it.
#include <stdio.h>
#include <stdlib.h>
#define MAX 10
typedef struct stack {
int elems[MAX];
int top;
} stack;
void Init(stack *s) {
if(!s)
return;
s->top = 0;
}
int IsEmpty(stack *s) {
return (s->top == 0);
}
void Push(stack *s, int elem) {
if (s->top == MAX) {
printf("Stack voll!");
return;
}
s->elems[s->top++] = elem;
}
int *Pop(stack *s) {
if (IsEmpty(s))
return NULL;
return &s->elems[--(s->top)];
}
int main() {
stack *s = malloc(sizeof *s);
Init(s);
printf("%d\n", s->top); // Ist 0 , OK
Push(s, 42);
int *v = Pop(s);
printf("%d\n", *v);
}
and example run:
0
42
Consider using a name prefix like "Stack" for all your symbols to avoid name conflicts.
In c we don't cast void * (from malloc()).
I am trying to implement on my own (in order to understand it better) the Stack data structure in C language.
Here is what I've got so far:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct stack{
//Data_Strucure: Stack of intgers
int *stack;
int size_of_stack;
int elem_in_stack;
};
struct stack *creat_stack(unsigned int);
int push(struct stack *, int);
int pop(struct stack *);
int empty(struct stack *);
int peek(struct stack *);
int main(int argc, char *argv[]){
int new_elem = 13;
struct stack *new_stack = creat_stack(5);
printf("%d %d\n", new_stack->size_of_stack, new_stack->elem_in_stack);
//Crashes from here
push(new_stack, new_elem);
printf("%d\n", new_stack->stack[new_stack->size_of_stack]);
}
struct stack *creat_stack(unsigned int size){
struct stack tmp;
struct stack *ret_stack = &tmp;
if((ret_stack->stack = malloc(sizeof(int) * size)) == NULL){
fprintf(stderr, "Unable to allocate memory for the Stack.\n");
exit(1);
}
ret_stack->size_of_stack = size;
ret_stack->elem_in_stack = 0;
return ret_stack;
}
int push(struct stack *stack, int nw_elem){
int pos = stack->size_of_stack - stack->elem_in_stack;
if(stack->size_of_stack == 0)
return 1;
stack->stack[pos] = nw_elem;
}
The compiler returns me no error. Though I don't understand why it crashes after push() is called.
Please, if possible, instead of solution code, can you just tell me where the error is? This way I can understand how it effect the whole program and try to solve it on my own (so next time won't happen again).
Thanks is advance for any of your usefull answers.
At least the function creat_stack is incorrect.
struct stack *creat_stack(unsigned int size){
struct stack tmp;
struct stack *ret_stack = &tmp;
//...
return ret_stack;
}
It returns a pointer to the local object tmp that will not be alive after exiting the function. So the returned pointer will be invalid and dereferencing such a pointer invokes undefined behavior.
Instead you could return the object itself from the function. That is the function declaration could look like
struct stack creat_stack(unsigned int size);
And in main you can write
struct stack new_stack = creat_stack(5);
Also the function push does not change the data member elem_in_stack And again it invokes undefined behavior because when elem_in_stack is equal to 0 then the function tries to write to memory outside the dynamically allocated array. That is in this case pos is equal to size_of_stack.
int push(struct stack *stack, int nw_elem){
int pos = stack->size_of_stack - stack->elem_in_stack;
if(stack->size_of_stack == 0)
return 1;
stack->stack[pos] = nw_elem;
}
The following code is generating pointer warnings and I am not sure how to fix it?
gcc -std=c11 -pg -g3 -ggdb -W -Wall -lefence -I. -o main.o -c main.c
main.c: In function ‘push_state’:
main.c:15:16: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
*++s->point = s->top;
^
main.c: In function ‘pop_state’:
main.c:19:11: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
s->top=*s->point--;
^
#include <stdio.h>
typedef struct stack{
int **point; // pointer to location in memory
int *memory[24]; // stack memory
int top;
int i;
}Stack;
void push_state(Stack *s){
s->top=s->i++;
*++s->point = s->top;
};
void pop_state(Stack *s){
s->top = *s->point--;
};
void get_top(Stack *s){
printf("Stack top: %d\n",s->top);
};
void start(){
Stack s;
s.point=&s.memory[0];
s.i=0;
push_state(&s);
get_top(&s);
pop_state(&s);
get_top(&s);
}
int main( int argc, char *argv[] ) {
start();
return 0;
}
As written in the warning, t->top is a integer but *++s->point is a pointer, so you cant convert integer to pointer.
Maybe you want this;
typedef struct stack{
int **point; // pointer to location in memory
int *memory[24]; // stack memory
int *top;
int i;
}Stack;
void push_state(Stack *s){
s->top=s->memory[s->i++];
*++s->point = s->top;
};
I am posting a solution to my problem:
The problem was that s.point=&s.memory[0]; was not correct it should be s.point=s.memory; also **point was not correct it should be *point and *memory[24]; should be *memory and declared dynamically. Thanks Jonathan Leffler for making me go back and rethink it by removing the extra * from **point.
#include <stdio.h>
#include <stdlib.h>
#define push(s) (*++s->point = s->top)
#define pop(s) (*s->point--)
#define look(s) (*s->point)
#define MALLOC(p,s) if(((p) = malloc(s * sizeof(p))) == NULL){ exit(EXIT_FAILURE); }
typedef struct stack{
int *point; // pointer to location in memory
int *memory; // stack memory
int top;
int i;
}Stack;
void push_state(Stack *s){
++(s->top);
push(s);
};
void pop_state(Stack *s){
s->top = pop(s);
};
void look_top(Stack *s){
printf("look %d, Stack top: %d\n",look(s), s->top);
};
void start(){
Stack s;
s.top=0;
MALLOC(s.memory,24);
//s.point=&s.memory[0]; <- wrong assignment
s.point=s.memory;
push_state(&s);
push_state(&s);
push_state(&s);
look_top(&s);
pop_state(&s);
look_top(&s);
pop_state(&s);
look_top(&s);
push_state(&s);
look_top(&s);
}
int main( int argc, char *argv[] ) {
start();
return 0;
}
I get a segfault while runnig this code to implement a stack in C. Please note that the code is kind of incomplete. I just wanted to check and see if I could push a few elements on to the stack and print them out. But it throws back a segfault. Any help would be much appreciated!!
#include<stdlib.h>
#include<stdio.h>
struct stack
{
int *elems;
int ll;
int al;
};
void stack_new(struct stack *s)
{
s->ll=0;
s->al=4;
s->elems=malloc(4*sizeof(int));
}
void stack_del(struct stack *s)
{
free(s->elems);
}
void stack_push(struct stack *s,int value)
{
if(s->ll==s->al)
{
printf("overflow");
/*s->al*=2;
s->elems=realloc(s->elems, s->al*sizeof(int));*/
}
s->elems[s->ll]=value;
s->ll++;
}
void stack_pop(struct stack *s)
{
s->ll--;
return (s->elems[s->ll]);
}
void main()
{
struct stack *s;
stack_new(s);
stack_push(s,3);
stack_push(s,4);
stack_push(s,8);
printf("%d", s->elems[0]);
//stack_pop(s);
//stack_del(s);
}
Declaring
struct stack *s;
doesn’t allocate any memory for a struct stack. Do that:
struct stack *s = malloc(sizeof *s);
Or just put your stack on the stack:
struct stack s;
stack_new(&s);
…
Using more descriptive field names is also a good idea.
You have several errors
You never initialize the pointer s in your main function, so in your stack_new function dereferencing s causes a segmentation fault.
You should allocate space for the stack first, wherever you want but you must.
Another thing is if you want to initialize your al field with a constant number and then allocate an array of constant size, you don't need the field al, and you can declare elems as int elems[CONSTANT_NUMBER] but if you want it to be dynamic, which is what I think you want from your check if(s->ll == s->al) in the stack_push function, then you can simply pass the value you want al to have to the stack_new function.
This is some of your code, fixed so you can see what I actually mean.
#include<stdlib.h>
#include<stdio.h>
struct stack
{
int *elems;
int ll;
int al;
};
struct stack *stack_new(int al) /* you can pass the maximum number of elements allowed */
{
struct stack *s;
s = malloc(sizeof(struct stack));
if (s == NULL)
return NULL;
s->ll = 0;
s->al = al;
s->elems = malloc(al * sizeof(int)); /* and you dynamically allocate space for them here */
return s;
}
void stack_del(struct stack *s)
{
if (s != NULL) /* always check the pointers to prevent `SEGMENTATION FAULT` */
{
if (s->elems != NULL)
free(s->elems);
free(s);
}
}
void stack_push(struct stack *s, int value)
{
if (s == NULL)
return;
if(s->ll == s->al)
{
printf("overflow");
/*s->al*=2;
s->elems=realloc(s->elems, s->al*sizeof(int));*/
}
if (s->elems != NULL)
s->elems[s->ll] = value;
s->ll++;
}
int stack_pop(struct stack *s)
{
if ((s == NULL) || (s->elems == NULL))
return 0;
s->ll--;
return (s->elems[s->ll]);
}
int main()
{
struct stack *s;
s = stack_new(4);
stack_push(s, 3);
stack_push(s, 4);
stack_push(s, 8);
printf("%d", s->elems[0]);
stack_pop(s);
stack_del(s);
return 0;
}
```
Hello i am trying to return a struct from a function but i cant find a way to do so without declaring the struct as global. How can this be done? Here is the code (THIS WORKS AS IT IS)
...
void log_in();
struct node
{
char name_log[20];
int passlog;
int user_point;
}tmp;
int main()
{
...
else if(sel=='2')
{
log_in();
if (tmp.passlog==TRUE)
logged_in(tmp.name_log,tmp.user_point); //and here i want to use the retun values
}
void log_in()
{
... //make the changes in the struct
}
...
What i want to achieve is to place the struct node declaration within main but sadly it wont work. So here is what i am trying to do: (THIS DOESN'T WORK)
...
struct node log_in();
int main() {
...
else if(sel=='2') {
struct node //here is where i want to declare
{
char name_log[20];
int passlog;
int user_point;
}tmp;
log_in();
if (tmp.passlog==TRUE)
logged_in(tmp.name_log,tmp.user_point); //and here i want to use the retun values
}
struct node log_in()
{
...
return tmp;
}
...
else if(sel=='2') //or within this block but I don't know how.
{ struct node tmp;
tmp=log_in();
if (tmp.passlog==TRUE)
logged_in(tmp.name_log,tmp.user_point); //and here I want to use the return values
}
and inside the function log_in()
struct node log_in()
{
struct tmp
...
return tmp;
}
use a local variable inside the function and return this variable. Assign it to another variable inside main().
Declare the structure first, then create the variable temp. Like this:
struct node
{
char name_log[20];
int passlog;
int user_point;
};
Then you can create the local variable like
struct node tmp;
Pass a pointer to the struct node to your log_in function and have it return a boolean value so the caller can check whether logging in succeeded or didn't. (Note I'm trying to guess what you want to achieve, and I might be guessing wrong.)
#include <stdio.h>
#include <string.h>
struct node {
char name_log[20];
int passlog;
int user_point;
};
int log_in(char, struct node *);
int log_in(char sel, struct node * tmp) {
int ret = 0;
if (sel == '2') {
ret = 1;
strcpy( tmp->name_log, "Gonzo" );
tmp->passlog = 33;
tmp->user_point = 99;
}
return ret;
}
int main(int argc, char ** argv) {
struct node tmp;
char sel = argv[1][0];
if ( log_in(sel, &tmp) ) {
// tmp initialized
printf( "%s, %d, %d\n", tmp.name_log, tmp.passlog, tmp.user_point );
}
else {
// tmp not initialized
}
}
Call passing 2 on the command line. (If you don't, undefined behaviour.)
If you want to use some struct in 2 different routines - you must declare it outside of both of them since they both have to see how this struct is structured.
BTW - you invoke log_in but do not use its return value.
You can't operate on a type that is unknown. If log_in() doesn't know the definition of struct node, it can't use it directly. The only thing it can do is somehow receive a pointer to a variable of this type and then either treat it as raw data (sequence of bytes) or cast said pointer to a pointer to a known to log_in() type and work with that.
You can also redefine struct node inside of log_in(), which is a way of making log_in() operate on a known type:
void log_in(void*);
void logged_in(char*, int);
int main(void)
{
int sel = '2';
if (sel == '2')
{
struct node
{
char name_log[20];
int passlog;
int user_point;
} tmp;
log_in(&tmp);
if (tmp.passlog)
logged_in(tmp.name_log, tmp.user_point);
}
return 0;
}
void log_in(void* n)
{
struct node
{
char name_log[20];
int passlog;
int user_point;
} *p = n;
p->passlog = 1;
}
void logged_in(char* name, int point)
{
}
If you don't want to pass tmp by a formal reference into log_in(), you must make it available globally. For example like this:
void log_in(void);
void logged_in(char*, int);
void* pTmp;
int main(void)
{
int sel = '2';
if (sel == '2')
{
struct node
{
char name_log[20];
int passlog;
int user_point;
} tmp;
pTmp = &tmp;
log_in();
if (tmp.passlog)
logged_in(tmp.name_log, tmp.user_point);
}
return 0;
}
void log_in(void)
{
struct node
{
char name_log[20];
int passlog;
int user_point;
} *p = pTmp;
p->passlog = 1;
}
void logged_in(char* name, int point)
{
}