【问题标题】:Create a dynamic allocated Linked List创建动态分配的链表
【发布时间】:2018-11-20 13:17:31
【问题描述】:

我正在尝试创建一个游戏,当用户进入游戏时,会为该玩家创建一个结构。 如果玩家输入其名称,游戏会提示玩家以下内容:

Type player name:> George
Choose one of the following Otions:
    [+]1) to remove George from player List.
    [+]0) to keep George.

玩家需要输入 3 个名称并决定是删除还是保留其中一个或全部。

我遇到的问题是,如果玩家决定从列表中删除一个或多个,我无法保留创建的(保留的)列表。

这是可以编译的程序的一部分:

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

#define PERCENT 5
#define LEFT "left"
#define RIGHT "Right"

struct node {
    int player_ID;
    struct node* prev;
    struct node* next;
    char move_player[256];
    char player_name[ 31 ];
} node;

struct node *root;
struct node *current;
struct node *player_node( int player_ID, const char *player_name );
void delete_player ( void *player_list );

int main( void )
{
    char name[256] = { 0 };
    int i = 0, clean;

    root = player_node( PERCENT, RIGHT );
    current =  root;

    do{
        struct node *player = player_node( PERCENT, LEFT );
        player->prev = current;
        current->next = player;
        current = player;

        printf( "Type player name:> ");
        if ( fgets( name, 256, stdin ) == NULL )
        {
            printf("Error, fgets()\n");
            exit( EXIT_FAILURE );
        }
        name[ strcspn( name, "\n" ) ] = '\0';
        strncpy( player->player_name, name, strlen( name ) );
        printf( "Choose one of the following Otions:\n" );
        printf( "\t[+]1) to remove %s from player List.\n", current->player_name );
        printf( "\t[+]0) to keep %s.\n", current->player_name );


        int opt = 0;
        if ( scanf( "%d", &opt) != 1 )
        {
            printf("Error, scanf()\n");
        }else if ( opt == 1 )
        {
            delete_player ( player );
        }
        while ( ( clean = getchar() ) != '\n' && clean != EOF );
        i++;
    }while( i < 3 );

    struct node *tmp = root->next;
    while ( tmp != NULL )
    {
        printf( "Name = %s", tmp->player_name );
        tmp = tmp->next;
    }
    free( root );
}

struct node *player_node( int player_ID, const char *const movement )
{
    struct node *player = malloc( sizeof( struct node ) );
    player->prev = NULL;
    player->next = NULL;
    player->player_ID = player_ID;
    strncpy( player->move_player, movement, strlen( movement) );
    strncpy( player->player_name, "NULL", 5 );
    return player;
}

void delete_player ( void *player_list )
{
    struct node *local_client = (struct node* )player_list;
    if ( local_client == current )
    {
        current = local_client->prev;
        current->next = NULL;
    } else
    {
        local_client->prev->next = local_client->next;
        local_client->next->prev = local_client->prev;
    }
    free( local_client );
}

如果代码达到这个:

struct node *tmp = root->next;
while ( tmp != NULL )
{
    printf( "Name = %s", tmp->player_name );
}

列表中没有剩余玩家,因为列表没有打印出来。

为什么列表是空的?

【问题讨论】:

  • strncpy(player-&gt;move_player, movement, strlen(movement));: 你没有复制 NUL 终止符。只需写strcpy(player-&gt;move_player, movement)。另请注意,strncpy 根本不是strcpy 的更安全替代方案,请仔细阅读strncpy 的文档,它不是您认为的那样。很可能还有其他错误。

标签: c string linked-list


【解决方案1】:

使用strcpy() 代替strncpy()。后者比前者是not safer

变化:

strncpy(player->player_name, name, strlen( name ));

到:

strcpy(player->player_name, name);

对这个调用做同样的事情:

strncpy( player->move_player, movement, strlen( movement) );

因为在这两种情况下,您都没有复制 NULL 终止符。

然后,当printf() 或任何标准字符串函数处理您的字符串时,它不知道何时停止...

您的问题的核心是[strlen()]3 计算字符串的长度,而不考虑 NULL 终止符:

C 字符串的长度由终止空字符确定:C 字符串与字符串开头和终止空字符之间的字符数一样长(不包括终止空字符本身)。

我还将strncpy( player-&gt;player_name, "NULL", 5 ); 更改为同质的。


如果你必须使用strncpy(),那么只需在第三个参数中加1,如下:

strncpy(player->player_name, name, strlen( name ) + 1);

但是,请记住,在此代码中使用 strncpy() 是没有意义的,只会降低可读性,因为它会增加复杂性并降低代码的简洁性。

【讨论】:

  • 错误。 strncpy 的用法在这里毫无意义。 strcpy 就足够了。 strncpy( player-&gt;player_name, name, strlen( name ) + 1); 等价于 strcpy( player-&gt;player_name, name);
  • @Jabberwocky 我自己会使用strcpy()。实际上,此答案的第一个版本使用了该功能。但是,在阅读 Why should you use strncpy instead of strcpy? 并考虑到 OP 必须对他们的代码进行的最小更改后,使用 strncpy() 进行编辑,因为了解该方法可能也是一个好习惯......我将编辑我的问题再次,但你认为它可以改进,请告诉我!
  • strncpy( player-&gt;move_player, movement, strlen( movement) + 1); 可能看起来比strcpy 更安全,但实际上并非......
  • @Jabberwocky 不是,你是对的。我回滚了我的答案,感谢您真的帮助我改进了这个答案!
  • @MichaelB。祝你好运。我有时会查看我们教授 8 年前教过的list management,以提醒我应该做什么。检查那里的免费功能可能对您有用。如果你有问题,请发布一个新的问题,如果你愿意,把链接分享给我,我可以帮忙,希望对你有帮助!
猜你喜欢
  • 1970-01-01
  • 2021-12-27
  • 1970-01-01
  • 2016-05-22
  • 1970-01-01
  • 2013-10-09
  • 1970-01-01
  • 2015-01-17
  • 2013-07-18
相关资源
最近更新 更多