在C链接列表练习,有什么不对?

时间:2016-02-22 02:54:26

标签: linked-list

下面的代码会编译,但它不会按预期运行。 我不确定我做错了什么,所以有人愿意告诉我我做错了什么以及我应该做得更好。 我需要更改什么才能使其正常运行?

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

typedef struct sub_Node
{
    int value;
    struct sub_Node *next;
}sub_Node;

typedef struct Node
{
    char *name;
    struct Node *next;
    struct sub_Node *sub_start;
}Node;
Node *start;


void add_player(char *name)
{
    Node *temp;
    temp = (Node *)malloc(sizeof(Node));
    temp->next = start;
    temp->name = name;
    temp->sub_start = (sub_Node *)malloc(sizeof(sub_Node));
    temp->sub_start->next = NULL;
    temp->sub_start->value = -1;
    start = temp;
}

void initialize()
{
    char *p;
    p = "\0";
    add_player(p);
}

void remove_player(char *name)
{
    Node *p;
    for(p = start; p!= NULL; p = p->next)
        if(p->name == name)
        {
            p->name = p->next->name;
            p->next = p->next->next;
        }
}

sub_Node* add_descending(sub_Node* sub_start, int piece_value)
{
    sub_Node *temp, *prev, *next;
    temp = (sub_Node *)malloc(sizeof(sub_Node));
    temp->value = piece_value;
    temp->next = NULL;
    prev = NULL;
    next = sub_start;
    while(next && next->value >= piece_value)
    {
        prev = next;
        next = next->next;
    }
    if(!next)
    {
        prev->next = temp;
    }
    else
    {
        if(prev)
        {
            temp->next = prev->next;
            prev->next = temp;
        }
        else
        {
            temp->next = sub_start;
            sub_start = temp;
        }
    }
    return sub_start;
}

void add_piece(char *name, int piece_value)
{
    Node *p;
    int c;
    for(p = start; p!=NULL; p = p->next)
        if(p->name == name)
            p->sub_start = add_descending(p->sub_start, piece_value);
}

void print_pieces(char *name)
{
    Node *p;
    sub_Node *q;
    for(p = start; p!=NULL; p = p->next)
        if(p->name == name)
        {
            printf("The values of the owned pieces are:");
            for(q = p->sub_start; q->value != -1; q = q->next)
                printf(" %d", q->value);
        }
}

int lose_piece(char *name)
{
    Node *p;
    sub_Node *q;
    int aux;
    for(p = start; p!=NULL; p = p->next)
        if(p->name == name)
        {
            for(q = p->sub_start; q->next->value != -1; q = q->next) {}
            aux = q->value;
            q->value = q->next->value;
            q->next = q->next->next;
            return aux;
        }
}

void print_players()
{
    Node *p;
    printf("The players are: ");
    for(p = start; p->name != "\0"; p = p->next)
        printf("%s ", p->name);
    printf("\n");
}

int main()
{
    initialize();
    int y, value;
    char name[20];
    printf("Insert a digit to execute the desired task:\n"
        "<0> end the program\n"
        "<1> add a player, who doesn't own any piece yet\n"
        "<2> remove a player and all his pieces\n"
        "<3> print the name of all the players\n"
        "<4> a player gets a piece\n"
        "<5> a player loses the piece with the lowest value out of the ones that he has\n"
        "<6> prints the pieces of a player in a descending order by value\n\n");
    do
    {
        printf("digit: ");
        scanf("%d", &y);
        switch(y)
        {
            case 1:
                printf("Insert the player's name: ");
                scanf("%s", name);
                add_player(name);
                break;
            case 2:
                printf("Insert the player's name: ");
                scanf("%s", name);
                remove_player(name);
                break;
            case 3:
                print_players();
                break;
            case 4:
                printf("Insert the player's name:  ");
                scanf("%s", name);
                printf("Insert the value of the piece: ");
                scanf("%d", value);
                add_piece(name, value);
                break;
            case 5:
                printf("Insert the player's name: ");
                scanf("%s", name);
                printf("\nThe player loses the piece: %d\n", lose_piece(name));
                break;
            case 6:
                printf("Insert the player's name: ");
                scanf("%s", name);
                print_pieces(name);
        }
    } while(y != 0);
    return 0;
}

1 个答案:

答案 0 :(得分:0)

这两个主要问题,scanf("%d", value);值应该通过引用传递,例如scanf("%d", &value);,第二个是c中的字符串比较,如代码p->name != "\0"if(p->name == name)这是错误的,因为实际上你在字符串的地址(它驻留在内存中)和字符串值之间进行比较。比较c中的字符串,你必须使用strcmp和家庭。

实际上有3个主要问题。像在temp->name = name;中那样设置字符串值比稍微复杂一点。因为您要从堆栈中为temp->name分配一个易失性的字符串(堆栈很快就会从函数返回时失效)。在您的情况下,您必须使用malloc(和朋友)或仅使用strdup分配新字符串。

这里是对您的程序进行略微改写的奖励,您会发现许多建议,并且是如何构建代码以便于维护的良好起点。

仍然建议您将成员和变量更改为更多声明性名称,如sub_startsub_Node分别为PieceNodepieces

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


typedef struct sub_Node
{
    int value;
    struct sub_Node *next;
}sub_Node;

typedef struct Node
{
    char *name;
    struct Node *next;
    struct Node *prev; // this to make life easyer
    struct sub_Node *sub_start;
}Node;


Node *start = NULL;


Node *find_player(char *name){
    Node *tmp = start;
    while( tmp ){
        if(strcmp(tmp->name,name) == 0 )
            break;
        tmp = tmp->next;
    }
    return tmp;
}

// int to return Error Code
// 
int add_player(char *name)
{
    Node *temp;
    if( find_player(name)) {
        printf("player %s already exists\n", name);
        return 1;
    }
    // do not cast malloc
    temp = malloc(sizeof(Node));

    if( !temp ){
        printf ("not enough memory\n");
        return 2;
    }

    temp->name = strdup ( name);    // here was your error
    temp->sub_start = NULL;         // keep it simple

    temp->prev = NULL;
    temp->next = start;

    if(start)
        start->prev = temp;

    start = temp;

    return 0; // no error
}


void DestroyPieces(sub_Node* piece){
    if( piece ) {
        DestroyPieces( piece->next );
        free( piece );
    }
}

// as usual use int to return error code
int remove_player(char *name)
{
    Node *player = find_player(name);
    if ( !player ){
        return 1; // player not found
    }

    if ( player->next ){
        player->next->prev = player->prev;
    }

    if ( player->prev ){
        player->prev->next = player->next;
    }

    DestroyPieces(player->sub_start);

    free(player->name);
    free(player);

    return 0; // success
}

sub_Node* new_piece(int value){
    sub_Node *temp = malloc( sizeof(sub_Node) );
    if(temp){
        temp->value = value;
        temp->next = NULL;
    }
    return temp;
}

// int to return error code
// pass sub_start as pointer to pointer, as it might be updated
int  add_descending(sub_Node** psub_start, int piece_value)
{
    sub_Node *piece, *current, *prev = NULL;

    if( !psub_start){
        return 5; // this should not happen
    }
    current = *psub_start;

    piece = new_piece( piece_value );
    if( !piece ) return 1; // no mem

    if(!current){
        // this is the first and only one
        *psub_start = piece;
        return 0; // OK
    }


    while(current && current->value >= piece_value)
    {
        prev        = current;
        current     = current->next;
    }

    if( prev )
        prev->next  = piece;

    piece->next = current;

    if( current == *psub_start ){
        *psub_start = piece;
    }
    return 0 ; // OK

}

void add_piece(Node * player, int piece_value)
{

    if ( !player) {
        return ;
    }

    if(add_descending (&(player->sub_start), piece_value) == 0 )
        return ; //OK

    printf("an error occured while adding a piece (%d) to player '%s'\n",piece_value,player->name);
}


void print_pieces(Node *player)
{

    sub_Node *q;

     if( !player ){
        return;
    }   


    if( !player->sub_start ){
        printf("Player '%s' has no pieces\n",player->name);
        return;
    }

    printf("The values of the owned pieces are:");
    for(q = player->sub_start; q != NULL; q = q->next)
        printf(" %d", q->value);

    printf("\n");

}

void lose_piece(Node *player)
{

    if( !player ){
        return;
    }

    sub_Node *q, *prev = NULL;
    int aux;


    if( !player->sub_start ){
        printf("Player '%s' has no pieces\n",player->name);
        return;
    } 


    // i think you want drop the last one
    for(q = player->sub_start; q->next != NULL ;prev = q, q = q->next) {
        ;
    }
    if(prev)
        prev->next = NULL;
    else
        player->sub_start = NULL;

    aux = q->value;
    free(q);

    printf("\nThe player loses the piece: %d\n", aux);
    return;

}

void print_players()
{
    Node *p;
    if( !start ){
        printf("there are no players, try to add some\n");
        return;
    }
    printf("The players are: ");
    for(p = start; p != NULL; p = p->next)
        printf("%s ", p->name);
    printf("\n");
}

void print_menu(void){
    printf("Insert a digit to execute the desired task:\n"
        "<0> end the program\n"
        "<1> add a player, who doesn't own any piece yet\n"
        "<2> remove a player and all his pieces\n"
        "<3> print the name of all the players\n"
        "<4> a player gets a piece\n"
        "<5> a player loses the piece with the lowest value out of the ones that he has\n"
        "<6> prints the pieces of a player in a descending order by value\n\n");
}

Node * get_player(char *name){

    Node *player = find_player(name);

    if(!player)
        printf("Player '%s' do not exists\n",name);

    return player;
}

int main()
{
    // initialize(); no more needed
    int     y, value;
    char    name[20];
    Node    *player;


    print_menu();
    do
    {
        printf("digit: ");
        scanf("%d", &y);

        switch(y)
        {
            case 1:
                printf("Insert the player's name: ");
                scanf("%s", name);
                add_player(name);
                break;
            case 2:
                printf("Insert the player's name: ");
                scanf("%s", name);
                player = get_player(name);
                if( player )


                break;
            case 3:
                print_players();
                break;
            case 4:
                printf("Insert the player's name:  ");
                scanf("%s", name);
                player = get_player(name);

                if( player ){
                    printf("Insert the value of the piece: ");
                    scanf("%d", &value);
                    add_piece(player, value);
                }

                break;
            case 5:
                printf("Insert the player's name: ");
                scanf("%s", name);

                player = get_player(name);
                lose_piece(player);

                break;
            case 6:
                printf("Insert the player's name: ");
                scanf("%s", name);
                player = get_player(name);
                print_pieces(player);
        }
    } while(y != 0);
    return 0;
}