简体   繁体   中英

Segmentation Fault when pushing string to the stack “ C ”

Sorry for such a basic question but I've been searching for an answer and can't find anything as to why this is happening.

Code below compiles with out errors when I go to push my first scanf to get a new char* and push it to the stack I get a segmentation error.

I can by pass the segmentation 11 error by passing &val when I call the push function. push(&val) but when I pass the address like this the new node doesn't store the new information. Example

I ask for string #1 --> Moon
push the value and print the stack
Moon Two One
I ask for a second String --> Work
Print the Stack and this happens
Work Work Two One

So i'm new to C and realize this has something to do with the pointers and passing by reference vs address vs contents(or so my conclusion) Maybe someone can point me in a good direction for pointers and references read I've read several already but I'm not sure why the code below isn't working. So maybe another read that I haven't found yet.

#include <stdio.h> //includes requried. 
#include <stdlib.h> 
#include <limits.h>
#include <ctype.h>
#include <string.h>
//defining node for stack
typedef struct node{
char *data;
struct node *pNext;
}node;
//defining functions
void push(char* a);
void printStack();
void error(char* msg);
//declaring global variables
node *pTop = NULL; //pointer to top of stack
//main function
int main(int charc, char* argv[]){

    char *val;
    push("One");
    push("Two");
    printStack();
    printf("Push a new String to the stack: ");
    scanf(" %s", val);
    push(val);
    printStack();
    printf("Push a new String to the stack: ");
    scanf(" %s", val);
    push(val);
    printStack();
}

void push(char* a) {
    if (pTop == NULL) {
        //stack empty, just set pTop to a new node:
        pTop = malloc(sizeof(node));
        pTop -> data = a;
        pTop -> pNext = NULL;
    } else {
        //make a new node:
        node *pNew = malloc(sizeof(node));
        pNew -> data = a;
        //assign this node's next pointer to the top node:
        pNew -> pNext = pTop;
        //this node is the new top of stack:
        pTop = pNew;
    }
}
void printStack() {
    //get temporary pointer:
    node *pTemp = pTop;
    if (pTemp == NULL) {
        error("Print error: stack empty");
        return;
    }
    //walk down the stack, printing each value:
    do {
        printf("%s ", pTemp -> data);
        pTemp = pTemp -> pNext;
    } while (pTemp != NULL);
    printf("\n");
}
void error(char* msg) {
    printf("%s\n", msg);
}

You are using an uninitialised variable .

char *val;
//...
scanf(" %s", val);

The address you pass to scanf will cause undefined behaviour. You must allocate some memory for scanf to use.

How did I spot this? The compiler issued a warning! +1 for providing MCVE .

It has already been pointed out that you didn't initialize *val and that using it would cause undefined behavior. Most implementations of C-compilers would give you a program where it would be pointing to a seemingly random memory address and it's just plain luck that your use of it in scanf(" %s", val); didn't result in a segmentation fault error.

But that's not the reason for the behavior you described (the first string entered being overwritten by the second one). The reason is:

  • each time you called scanf(" %s", val); , it wrote to the same memory address because val was never given a new address to point to.
  • pTop -> data = a; does not copy the string. It just makes pTop -> data point to the same memory address as a does.

The solution to that is to either give val a new address (eg the one returned by malloc() ) each time you want to get a new string. Or even better, have push() copy the string by changing:

pTop -> data = a;

to:

size_t size = strlen(a) + 1;
pTop -> data = malloc(size);
if (pTop -> data) {
    memcpy(pTop -> data, a, size);
} else {
    // handle error. E.g. exit(1)
}

(or this if you're programming for a POSIX system:

pTop -> data = strdup(a); // Remember to check for error

).

Just remember that:

  • you have to free() all those strings after use.
  • you must make sure scanf() does not write more to val than it has space for.

it seem's you didn't use malloc to allocate memory for the strings. so when u exit the push function, the data which is on the stack (the real one) is deleted and no longer accessible. for each pointer in the struct, you should use malloc.

please try to malloc for the strings aswell.

Ok this is what I have done so far to get it to push a string properly to the stack. My issue is the coding is redundant and I don't think would make sense for large scale project of any sort. I have my interest in C because I'm coming back to coding after 10 years of being away. I use to know Java very well VB, javascript and tinkered with SQL queries. Decided to get back in to everything and want to learn C in and out due to it works directly with memory locations unlike other languages.

This is my modified code from above you will see I've given malloc to my char* but you will see I have some repetitive code involved to push my strings. When I change this to a int, float I don't have to use the malloc or null. I can just push and it works fine when I scanf for their int

When making malloc in my push function it prints the following still. Not sure what to do can only get it to store the new string if I malloc in the main function each time before i scanf.

FOUR FOUR TWO ONE when i go printStack(); with code below

#include <stdio.h> //includes requried. 
#include <stdlib.h> 
#include <limits.h>
#include <ctype.h>
#include <string.h>
//defining node for stack
typedef struct node{
char *data;
struct node *pNext;
}node;
//defining functions
void push(char* a);
void printStack();
void error(char* msg);
//declaring global variables
node *pTop = NULL; //pointer to top of stack
//main function
int main(int charc, char* argv[]){
    char* val = malloc(256);
    push("One");
    push("Two");
    printStack();
    printf("Push a new String to the stack: ");
    scanf(" %s", val);
    push(val);
    printStack();
    //val = malloc(256); //this doesn't seem proper coding reptitive 
    printf("Push a new String to the stack: ");
    scanf(" %s", val);
    push(val);
    printStack();
    free(val);
} //Memory Leaks maybe?

void push(char* a) {
    if (pTop == NULL) {
        //stack empty, just set pTop to a new node:
        pTop = malloc(sizeof(node));
        pTop -> data = a;
        pTop -> pNext = NULL;
    } else {
        //make a new node:
        //printf("line46-Pushing: %s\n",a);
        node *pNew = malloc(sizeof(node));
        pNew -> data = malloc(sizeof(a));
        pNew -> data = a;
        //assign this node's next pointer to the top node:
        pNew -> pNext = pTop;
        //this node is the new top of stack:
        pTop = pNew;
        //free(t);
    }
}
void printStack() {
    //get temporary pointer:
    node *pTemp = pTop;
    if (pTemp == NULL) {
        error("Print error: stack empty");
        return;
    }
    //walk down the stack, printing each value:
    do {
        printf("%s ", pTemp -> data);
        pTemp = pTemp -> pNext;
    } while (pTemp != NULL);
    printf("\n");
}
void error(char* msg) {
    printf("%s\n", msg);
}

Ok I know this isn't a huge accomplishment but I've finally got what I would think is logically an ok way to do this. I really just would appreciate a C expert to take a look over what I came up with and point out any bad habits or things that could cause problems later down the line. I appreciate the help from everyone.

#include <stdio.h> //includes requried. 
#include <stdlib.h> 
#include <limits.h>
#include <ctype.h>
#include <string.h>
//defining node for stack
typedef struct node{
char *data;
struct node *pNext;
}node;
//defining functions
void push(char* a);
void printStack();
void error(char* msg);
char* pop();
//declaring global variables
node *pTop = NULL; //pointer to top of stack
//main function
int main(int charc, char* argv[]){
    printf("Welcome to fun with stacks to get a list of full commands enter 'HELP'\n");
    char* val;
    char* usr_chc = malloc(256);
    do{
        printf("Enter your choice to PUSH, POP, PRINT or EXIT\n");
        scanf("%s",usr_chc);
        if(strcmp(usr_chc,"PUSH")==0 || strcmp(usr_chc,"push")==0){
            val = malloc(256);
            printf("Push a new String to the stack: ");
            scanf(" %s", val);
            push(val);
            printStack();
        }else if(strcmp(usr_chc,"POP")==0 || strcmp(usr_chc,"pop")==0  ){
            pop();   
        }else if(strcmp(usr_chc,"PRINT")==0 || strcmp(usr_chc,"print")==0){
            printStack();
        }else if(strcmp(usr_chc,"HELP")==0 || strcmp(usr_chc,"help")==0){
            printf("The list of commandds\n POP - to pop the top node off the stack\n PUSH to add new data to the stack \n PRINT - Print the stack data\n EXIT to quit the program\n");
        }
    }while(strcmp(usr_chc,"EXIT")!=0);
} //Memory Leaks maybe?

void push(char* a) {
    if (pTop == NULL) {
        //stack empty, just set pTop to a new node:
        pTop = malloc(sizeof(node));
        pTop -> data = a;
        pTop -> pNext = NULL;
    } else {
        //make a new node:
        //printf("line46-Pushing: %s\n",a);
        node *pNew = malloc(sizeof(node));
        pNew -> data = a;
        //assign this node's next pointer to the top node:
        pNew -> pNext = pTop;
        //this node is the new top of stack:
        pTop = pNew;
        //free(t);
    }
}
void printStack() {
    //get temporary pointer:
    node *pTemp = pTop;
    if (pTemp == NULL) {
        error("Print error: stack empty");
        return;
    }
    //walk down the stack, printing each value:
    do {
        printf("%s ", pTemp -> data);
        pTemp = pTemp -> pNext;
    } while (pTemp != NULL);
    printf("\n");
}
void error(char* msg) {
    printf("%s\n", msg);
}
char* pop() {
    //is the stack empty?
    if (pTop == NULL) {
        error("Pop error: stack empty");
        return NULL;
    } else {
        char *retVal = pTop -> data;
        //temp pointer to top
        node *pTemp = pTop;
        //set pTop to next node:
        pTop = pTop -> pNext;
        //free temp node:
        free(pTemp);
        return retVal;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM