2011-05-26 10 views
2

私はcプログラムを書いてコンパイルし、正常に動作しました。いくつかのコンパイルの後で、それは私にセグメンテーションフォールトを与え始めました。私はフォルダーの名前を変更し、再コンパイルして、再び機能しました。
これは正常ですか?一貫性のないセグメンテーションフォルトを持つには?私は、出力名を変更フォルダ名などを変更し、セグメンテーションフォールトを与えないようにセグメンテーションフォールトを与えるからバウンスする。もう何をすべきかわからない。
つまり、コーディングの問題であれば、segフォールトは一貫していなければなりません。私は毎回それを取得する必要があります。ここではコードです:
ファイル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; 
} 

ファイル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"); 
} 

ファイル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); 

ですstdin、それらをリストに入れて(重複なし)、それを印刷します。私は動的配列のリストを使用します。

答えて

6

変数を初期化してください!

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

ADD:一貫性のない動作は、リリースのコンパイル対デバッグから来ることができるが、通常、問題がすぐに見えるようにする0xDDDDDDDDのような奇妙な値に未初期化変数を設定し、デバッグモードでのコンパイラ。リリースモードでは、メモリブロックがゼロにされた場合、変数の内容は0になりますが、保証はありません。

+0

それはそれを修正するようです。ポインタが初期化されていないことはわかりませんでした。しかし、私はそれがデバッグ/リリースの矛盾を引き起こすとは思わない、私は同じメイクファイルをすべてのコンパイルを使用しています。 (および-gフラグなし) – Danish94

+0

-gフラグはデバッグ情報を含めるかどうかを指示しますが、実際にはデバッグビルド(最適化なし)を行います。 '-O0'(またはまもなく' -O')をコンパイルスイッチとして使用します。これらの条件下では、コンパイラはさらに多くの警告を報告します。おそらく、この場合初期化されていない問題です。デバッグ情報を持つ最適化された実行可能ファイルを持つことができます。-gは、シンボルを追加するかどうかのみを指示しますが、最適化されていないデバッグビルドは持っていません。 '-Wall'を使ってすべての警告を有効にすることも考えてください。 – jdehaan

+0

リリースには何が必要ですか? -O3? – Danish94

1

c/C++プログラムで断続的なsegfaultsは通常、ポインタ変数で初期化されていないメモリによって引き起こされます。

あなたは多くのコードを投稿しました。これは、読んでいるだけではデバッグが難しくなります。私はコードを調べ、変数が宣言されているところであれば、それに初期値(例えばゼロまたはNULL)を与えることをお勧めします。コンパイラはそれらを初期化しないことに注意してください。

numheadの値をmain()に初期設定することから始めてください。例えば。

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

EDIT 1

別のバグがaddToList()です。その関数内の最初のifブロックが実行されない場合、後でrealloc(p->arr, ...)を呼び出すと、ローカル変数pの値は初期化されません。 pを参照解除すると、p->arr, if p`が初期化されていない場合は、となります。 segfaultを取得します。

  1. 常にあなたがそれらを宣言する時点で変数を初期化:2つの

    二つの有用な技術C/C++でプログラミング

    EDIT。そうしないと、その値は未定義です。これはすべての問題を解決するわけではないことに注意してください。初期化されていないポインタを参照解除すると、が通常になります。それをヌルに初期設定してから逆参照すると、常にセグメンテーションが発生します。デバッグは簡単ですが、それでもクラッシュします。

  2. 常に、変数を最初に使用したコード内のポイントにできるだけ近い値で宣言します。これは、コンパイラが「宣言されていない変数」エラーを生成するため、初期化されていない変数を使用する機会を減らす効果があります。関数の開始時にすべての変数を宣言する習慣は、古いスタイル'K&R' Cからの二日酔いです。現代Cはそれを必要としません。代わりにそう

、:それは(メモリのうち)NULLを返すのケースであなたはmalloc()からの戻り値をチェックする必要があります

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

最初のifブロックの全体点は、メソッドが最初に呼び出されたときに実行され、pを初期化します。 – Danish94

+0

@ Danish94私はそれを理解しています。 'add'List()の最初の' if'ブロックは、 'h'が指す値がnullの場合にのみ実行されます。 'head'を初期化していると仮定すると、これは' addToList() 'が初めて呼ばれたときに発生します。しかし、その後の 'addToList()'呼び出しで 'h'の値はnullでなく' p'は初期化されず、 'realloc()'の呼び出しでinを使用すると問題が発生します。 –

+0

@AndyJohnsonしかし、それはaddToListの複数の呼び出しでそれを保持するために静的なものなので、後続の呼び出しでpはまだ初期化されています。 – Danish94

1

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

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

のような何かを試してみてください。

+0

チェックされていない唯一のmallocは、addToList関数の最初のifであり、1回だけ実行し、1つのstructと1つのintを割り当てます。複数回実行されるreallocとmallocがチェックされます。 – Danish94

+0

@ Danish94 addToList()の最後のif(){}にチェックされていない別のmallocがあります。 –

+0

ああ、そのことについて忘れてしまった、ありがとう。 – Danish94

関連する問題