为什么这个分段错误在各个版本中不一致?

发布于 2024-11-09 20:08:23 字数 4123 浏览 0 评论 0原文

我写了一个ac程序,编译了它,运行得很好。经过几次编译后 - 它开始给我一个分段错误。我重命名了该文件夹,重新编译,它再次工作。
这是正常现象吗?出现不一致的分段错误?我更改输出名称,更改文件夹名称等......并且它从给出分段错误跳到不给出分段错误。我不知道该怎么办了。
我的意思是,如果是编码问题,seg failure应该是一致的,对吧?我每次都应该得到它。这是代码:
file my_set.c:

#include <stdio.h>
#include <stdlib.h>
#include "list.h"

/*
The program acceps a set of numbers from stdin until EOF
And then prints them (not storing duplicate numbers)
*/

int main ()
{
    int num; 
    nodePtr head; /*head of the list*/

    while (scanf("%d", &num) != EOF)
    {
        addToList(num, &head);
    }
    printList(head);
    freeList(head);
    return 0;
}

file list.c:

#include <stdio.h>
#include <stdlib.h>
#include "list.h"

/*
Implements a linked list, each element of which contains a dynamic array.
I used a linked list to maximize potential memory in case it is fragmented.
I use a dynamic array in each node to minimize the percentage of overhead
from creating a list (the pointer, the index...);
*/

/*
Adds number n to list *h
4 cases:
1. list is empty:
    creating one
    updating h with new list
    creating a new dynamic array in the list
    updating it and the index
2. can reallocate current node's array for 1 more int
3. cannot reallocate current node's array:
    creating a new node
    initializing it
4. cannot create a new node
    printing the current list, an "out of memory error" and freeing all memory.
*/
void addToList(int n, nodePtr *h)
{
    static nodePtr p; /*points to current last node*/
    int *temp; /*for use in reallocation*/

    if (!*h) /*first item of set*/
    {
        *h = malloc (sizeof(node));
        (*h)->arr = malloc(sizeof(int));
        (*h)->arr[0] = n;
        (*h)->i = 1;
        p = *h;
        return;
    }

    /*if n is already in the list, no need to add it
    the call comes after first item, because first item cannot be in the list*/
    if(existsInList(n, *h)) return;

    /*using realloc while still possible*/
    if ((temp = realloc(p->arr, (p->i+1)*sizeof(int))))
    {
        p->arr = temp;
        p->arr[p->i] = n;
        p->i++;
        return;
    }

    /*if  realloc no longet possible - start new node*/
    if ((p->next = malloc(sizeof(node))))
    {
        p = p->next;
        p->arr = malloc(sizeof(int));
        p->arr[0] = n;
        p->i = 1;
        return;
    }

    /*can no longer start new nodes - quit with error, after printing*/
    printf("out of memory!");
    printList(*h);
    freeList(*h);
}

/*checks if n is in p assuming p is not null
it can asume so because the call for it comes after the check for first item*/
int existsInList(int n, nodePtr p)
{
    int i;
    for (; p ; p = p->next)
        for (i = 0; i < p->i; i++)
            if (p->arr[i] == n)
                return 1;
    return 0;
}

/*frees the list*/
void freeList(nodePtr p)
{
    nodePtr temp = p;

    if (!p) return; /*list is empty*/

    while (p)
    {
        free(p->arr);
        p = p->next;
        free(temp);
    }
}

/*prints the content of the list to stdout*/
void printList(nodePtr p)
{
    if (!p) return;
    int i;
    printf("\n");
    for (; p ; p = p->next)
        for (i = 0; i < p->i; i++)
            printf("%d ", p->arr[i]);   
    printf("\n");
}

file list.h:

/*
pointer to a node
declare a variable of this type to create a list
then start adding to the list
*/
typedef struct s *nodePtr;

/*the struct that represents each node of the list
reason for dynamic array is in "list.c"
*/
typedef struct s
{
    int *arr;
    int i; /*index for next num, also size of array;*/
    nodePtr next;
}node;

/*Adds the int to list at nodePtr omitting duplicates*/
void addToList(int, nodePtr*);
/*prints a list*/
void printList(nodePtr);
/*returns 1 if an int exists in list referenced by nodePtr, 0 otherwise*/
int existsInList(int, nodePtr);
/*frees all dynamically allocated memory*/
void freeList(nodePtr);

基本上我所做的就是从标准输入获取数字,将它们放入列表中(没有重复项),然后打印它们。我使用动态数组列表。

I wrote a c program, compiled it and it ran fine. After a few compiles - it started giving me a segmentation fault. I renamed the folder, recompiled and it worked again.
Is this something normal? To have an inconsistent segmentation fault? I change the output name, change folder names etc.. and it bounces from giving segmentation fault to not giving seg fault. I don't know what to do anymore.
I mean, if it is a coding problem, seg fault should be consistent, right? I should get it every time. here's the code:
file my_set.c:

#include <stdio.h>
#include <stdlib.h>
#include "list.h"

/*
The program acceps a set of numbers from stdin until EOF
And then prints them (not storing duplicate numbers)
*/

int main ()
{
    int num; 
    nodePtr head; /*head of the list*/

    while (scanf("%d", &num) != EOF)
    {
        addToList(num, &head);
    }
    printList(head);
    freeList(head);
    return 0;
}

file list.c:

#include <stdio.h>
#include <stdlib.h>
#include "list.h"

/*
Implements a linked list, each element of which contains a dynamic array.
I used a linked list to maximize potential memory in case it is fragmented.
I use a dynamic array in each node to minimize the percentage of overhead
from creating a list (the pointer, the index...);
*/

/*
Adds number n to list *h
4 cases:
1. list is empty:
    creating one
    updating h with new list
    creating a new dynamic array in the list
    updating it and the index
2. can reallocate current node's array for 1 more int
3. cannot reallocate current node's array:
    creating a new node
    initializing it
4. cannot create a new node
    printing the current list, an "out of memory error" and freeing all memory.
*/
void addToList(int n, nodePtr *h)
{
    static nodePtr p; /*points to current last node*/
    int *temp; /*for use in reallocation*/

    if (!*h) /*first item of set*/
    {
        *h = malloc (sizeof(node));
        (*h)->arr = malloc(sizeof(int));
        (*h)->arr[0] = n;
        (*h)->i = 1;
        p = *h;
        return;
    }

    /*if n is already in the list, no need to add it
    the call comes after first item, because first item cannot be in the list*/
    if(existsInList(n, *h)) return;

    /*using realloc while still possible*/
    if ((temp = realloc(p->arr, (p->i+1)*sizeof(int))))
    {
        p->arr = temp;
        p->arr[p->i] = n;
        p->i++;
        return;
    }

    /*if  realloc no longet possible - start new node*/
    if ((p->next = malloc(sizeof(node))))
    {
        p = p->next;
        p->arr = malloc(sizeof(int));
        p->arr[0] = n;
        p->i = 1;
        return;
    }

    /*can no longer start new nodes - quit with error, after printing*/
    printf("out of memory!");
    printList(*h);
    freeList(*h);
}

/*checks if n is in p assuming p is not null
it can asume so because the call for it comes after the check for first item*/
int existsInList(int n, nodePtr p)
{
    int i;
    for (; p ; p = p->next)
        for (i = 0; i < p->i; i++)
            if (p->arr[i] == n)
                return 1;
    return 0;
}

/*frees the list*/
void freeList(nodePtr p)
{
    nodePtr temp = p;

    if (!p) return; /*list is empty*/

    while (p)
    {
        free(p->arr);
        p = p->next;
        free(temp);
    }
}

/*prints the content of the list to stdout*/
void printList(nodePtr p)
{
    if (!p) return;
    int i;
    printf("\n");
    for (; p ; p = p->next)
        for (i = 0; i < p->i; i++)
            printf("%d ", p->arr[i]);   
    printf("\n");
}

file list.h:

/*
pointer to a node
declare a variable of this type to create a list
then start adding to the list
*/
typedef struct s *nodePtr;

/*the struct that represents each node of the list
reason for dynamic array is in "list.c"
*/
typedef struct s
{
    int *arr;
    int i; /*index for next num, also size of array;*/
    nodePtr next;
}node;

/*Adds the int to list at nodePtr omitting duplicates*/
void addToList(int, nodePtr*);
/*prints a list*/
void printList(nodePtr);
/*returns 1 if an int exists in list referenced by nodePtr, 0 otherwise*/
int existsInList(int, nodePtr);
/*frees all dynamically allocated memory*/
void freeList(nodePtr);

Basically all I do is get numbers from stdin, put them in a list(no duplicates) and then print them. I use a list of dynamic arrays.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

谢绝鈎搭 2024-11-16 20:08:23

初始化你的变量!

int num = 0;  
nodePtr head = NULL; /*head of the list*/

添加:不一致的行为可能来自调试与发布编译,通常调试模式下的编译器将未初始化的变量设置为奇怪的值,例如 0xDDDDDDDD 以使问题立即可见。在释放模式下,如果内存块被清零,将会发生变量内容为0的情况,但不能保证这一点。

Initialize your variables!

int num = 0;  
nodePtr head = NULL; /*head of the list*/

ADD: The inconsistent behaviour can come from debug vs release compilation, usually compilers in debug mode set the non-initialized variables to weird values like 0xDDDDDDDD to make the problem immediately visible. In release mode if the memory block is zeroed it will happen that the content of the variables is 0 but there is no guarantee for it.

女皇必胜 2024-11-16 20:08:23

您应该检查 malloc() 的返回值,以防它返回 NULL(内存不足)。

You should check the returns values from malloc() in case it's returning NULL (out of memory).

演出会有结束 2024-11-16 20:08:23

C/C++ 程序中的间歇性段错误通常是由未初始化的内存引起的,通常是在指针变量中。

您发布了很多代码,这使得仅仅阅读它们就很难进行调试。我建议仔细检查代码,并在声明变量的任何位置为其指定一个初始值(例如零或 NULL)。请记住,编译器不会为您初始化它们。

您可能应该首先在 main() 中初始化 numhead 的值。例如

int num = 0; 
nodePtr head = NULL; /*head of the list*/

EDIT 1

另一个错误是在addToList()中。如果该函数中的第一个 if 块未执行,则当您稍后调用 realloc(p->arr 时,局部变量 p 的值将未初始化,...)。当您取消引用 p 来获取 p->arr 时,如果p` 未初始化,那么您通常会遇到段错误。

编辑 2

在 C/C++ 中编程时的两个有用技巧:

  1. 始终在声明变量时初始化变量。如果不这样做,那么它们的值是未定义的。请注意,这并不能解决所有问题。如果您取消引用未初始化的指针,那么您通常会遇到段错误。如果你将它初始化为 null 然后取消引用它,那么你总是会遇到段错误。调试起来比较容易,但仍然会崩溃。
  2. 始终在尽可能靠近代码中首次使用变量的位置声明变量。这具有减少使用未初始化变量的机会的效果,因为编译器将生成“未声明的变量”错误。在函数开头声明所有变量的做法是旧式 'K&R' C,你必须这样做。现代 C 不需要它。

所以,不要:

int foo()  // Warning: bad code
{
    int a;
    int b;

    func1();
    a=func2(&b);
    return a;
}

尝试类似的事情:

int foo()
{
    func1();
    int b = 42;
    int a = func2(&b);
    return a;
}

Intermittent segfaults in c/c++ programs are usually caused by uninitialised memory, often in pointer variables.

You've posted a lot of code, which makes it hard to debug just be reading it. I suggest going through the code and, wherever a variable is declared, giving it an initial value (e.g. zero or NULL). Remember that the compiler will not initialise them for you.

You should probably start by initialising the values of num and head in main(). E.g.

int num = 0; 
nodePtr head = NULL; /*head of the list*/

EDIT 1

Another bug is in addToList(). If the first if block in that function is not executed then the value of the local variable p will be uninitailised when you later call realloc(p->arr, ...). When you dereference p to get p->arr, ifp` is uninitialised then you will usually get a segfault.

EDIT 2

Two useful techniques when programming in C/C++ :

  1. Always initialise variables at the point that you declare them. If you don't then their value is undefined. Note that this doesn't solve all problems. If you dereference an uninitialised pointer then you will usually get a segfault. If you initailise it to null and then dereference it then you will always get a segfault. Easier to debug, but it still crashes.
  2. Always declare variables as near as possible to the point in the code that you first use them. This has the effect of reducing the chances of using an uninitialised variable because the compiler will generate an 'undeclared variable' error. The practice of declaring all variables at the start of a function is a hangover from old-style 'K&R' C, where you had to do that. Modern C doesn't require it.

So, instead of:

int foo()  // Warning: bad code
{
    int a;
    int b;

    func1();
    a=func2(&b);
    return a;
}

try something like:

int foo()
{
    func1();
    int b = 42;
    int a = func2(&b);
    return a;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文