0

非常に単純なリンク リストを作成したところ、自分のコードとの出力の違いにtcc filename.c気付きました。tcc filename.c -run

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct llist {
    struct llist *next;
    struct llist *last;
    struct llist *first;
    int value;
    int item;
    int *length;
};

struct llist *newList(int v){

    struct llist *l1 = malloc(sizeof(struct llist)); 
    l1 -> length = malloc(sizeof(int));
    *l1 -> length = 1;

    l1 -> value = v;    
    l1 -> item = 0;    
    l1 -> first = l1;

    return l1;
}

struct llist *appendList(struct llist *l1, int v){

    struct llist *l2 = malloc(sizeof(struct llist));

    l2 -> value = v;
    l2 -> last = l1;
    l2 -> first = l1 -> first;
    l2 -> length = l1 -> length; 
    *l2 -> length += 1; 
    l2 -> item = l1 -> item + 1;

    l1 -> next = l2;

    return l2;    
};

int main(){
    struct llist *list = newList(4);
    list = appendList(list, 6);
    list = appendList(list, 8);
    list = appendList(list, 10);

    list = list -> first;

    int end = 0;
    while(end==0){

        printf("VAL: %d\n", list -> value);

        if(list -> next == NULL){
            printf("END\n");
            end = 1;
        }else{

            list = list -> next;
        }
    }


    return 0;
}

コンパイルしtcc filename.cてから実行すると、期待どおりの出力が生成されます。

VAL: 4
VAL: 6
VAL: 8
VAL: 10
END

これは、GCC と clang で得られる出力でもあります。

私が使用すると、次のようtcc filename.c -runになります。

VAL: 4
VAL: 6
VAL: 8
VAL: 10
VAL: 27092544
VAL: 1489483720
VAL: 0
END

最後の数値は常にゼロで、他の 2 つの余分な値は実行するたびに異なります。

関数と関数に追加l1 -> next = NULL;するソリューションを見つけました。newListl2 -> next = NULL;appendList

しかし、なぜ出力に違いがあるのか​​ 疑問に思っていました。NULLコンパイラにバグがありますか、それともほとんどのコンパイラで動作するにもかかわらずポインタを初期化しないのは間違っていましたか?

4

3 に答える 3

1

関数と関数に追加l1 -> next = NULL;する ソリューションを見つけました。newListl2 -> next = NULL;appendList

しかし、なぜ出力に違いがあるのか​​ 疑問に思っていました。NULLコンパイラにバグがありますか、それともほとんどのコンパイラで動作するにもかかわらずポインタを初期化しないのは間違っていました か?

ポインターの値に割り当てずにアクセスしたり、明示的または暗黙的に初期化したりするのは間違っていました (値の割り当てとは異なります)。これを行うと、未定義の動作が発生します。それにもかかわらず、ある状況下で期待した動作をプログラムがたまたま示したということは、あり得るもっともらしい結果ですが、それはプログラムを検証するものではありません。

さらに、元のアプローチは、より複雑な状況でテストした他のコンパイラーでは確実に機能しないことがわかります(ただし、「未定義」であるため、それについては確率的なステートメントしか作成できません)。

于 2017-07-07T17:54:56.797 に答える