将字符串推送到堆栈“C”时出现分段错误

时间:2017-06-11 18:50:05

标签: c pointers

对于这样一个基本问题我很抱歉,但我一直在寻找答案,但却找不到发生这种情况的原因。

下面的代码在我推送第一个scanf以获取新的char *并将其推送到堆栈时编译出错误我得到了分段错误。

我可以通过在调用push函数时传递& val来传递分段11错误。 push(& val)但是当我像这样传递地址时,新节点不存储新信息。实施例

我要求字符串#1 - >月亮
推送值并打印堆栈
月亮二一 我要求第二个字符串 - >工作
打印堆栈,这发生了 工作二一一

所以我是C的新手并且意识到这与指针有关,并且通过引用传递vs地址vs内容(或者我的结论)也许有人可以指出我的指针和参考的好方向阅读我'已经阅读了几个,但我不确定为什么下面的代码不起作用。也许还有另一个我尚未发现的读物。

#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);
}

5 个答案:

答案 0 :(得分:2)

您使用的是未初始化的变量

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

传递给scanf的地址将导致未定义的行为。您必须为scanf分配一些内存才能使用。

我是如何发现这一点的?编译器发出警告!提供MCVE的+1。

答案 1 :(得分:1)

已经指出你没有初始化*val并且使用它会导致未定义的行为。 C编译器的大多数实现都会给你一个程序,它会指向一个看似随机的内存地址,而且很幸运,你在scanf(" %s", val);中使用它并不会导致分段错误。

但这不是你所描述的行为的原因(输入的第一个字符串被第二个字符串覆盖)。原因是:

  • 每次调用scanf(" %s", val);时,它都会写入相同的内存地址,因为val从未获得指向的新地址。
  • pTop -> data = a;不会复制字符串。它只是使pTop -> data指向与a相同的内存地址。

解决方案是每次要获取新字符串时,为val提供一个新地址(例如malloc()返回的地址)。或者甚至更好,让push()通过更改:

来复制字符串
pTop -> data = a;

为:

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)
}

(或者,如果你正在为POSIX系统编程,那就是这个:

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

)。

请记住:

  • 使用后你必须free()所有这些字符串。
  • 您必须确保scanf()不会向val写入超出其余空间的内容。

答案 2 :(得分:0)

你似乎没有使用malloc为字符串分配内存。 所以当你退出推送功能时,堆栈上的数据(真实数据)将被删除,不再可访问。 对于struct中的每个指针,你应该使用malloc。

请尝试使用malloc作为字符串。

答案 3 :(得分:0)

好的,这就是我到目前为止所做的事情,以便将字符串正确地推送到堆栈。我的问题是编码是多余的,我认为对于任何类型的大型项目都没有意义。我对C感兴趣,因为我在离开10年后回到了编码状态。我用VB很好地了解Java,javascript并修改了SQL查询。决定回到一切,并希望学习C进出,因为它与其他语言不同,直接与内存位置一起工作。

这是我从上面修改过的代码,你会看到我已经将malloc给了我的char *但是你会看到我有一些重复的代码来推动我的字符串。当我将其更改为int时,浮动我不必使用malloc或null。我可以推动它,当我扫描他们的int

时,它工作正常

在我的推送功能中制作malloc时,它会打印以下内容。不知道该怎么办只能让它存储新的字符串,如果我每次在scanf之前在main函数中使用malloc。

当我去printStack()时,四个一个;代码如下

#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);
}

答案 4 :(得分:0)

好的,我知道这不是一个巨大的成就,但我终于得到了我认为逻辑上可行的方法。我真的很感激C专家看看我提出的问题,并指出任何可能在以后引起问题的坏习惯或事情。我感谢大家的帮助。

#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;
    }
}