首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >结构指针C语言

结构指针C语言
EN

Stack Overflow用户
提问于 2019-05-23 00:30:16
回答 1查看 88关注 0票数 2

我试图将值加载到我的结构中,但它将每个新结构的第一个元素附加到前一个结构的最后一个元素。

最初,我将'godiste‘字段作为一个int,并注意到它不起作用,所以我将其更改为char,并注意到出于某种原因,我的输入函数'upis’将igraci的'Ime‘的第二个成员的值附加到第一个成员的'godiste’。似乎不明白为什么会发生这种事。

我在main中放了一个printf,这个printf只是打印igraci成员0的'godiste‘,以确保它不是我的编写函数'ispis’的问题,而且它实际上是将'godiste‘的值设置为成员0的'godiste’+成员1的'ime‘。

‘'ime’是球员的名字'prezime‘是球员的姓氏'pozicija’是球员的位置'godiste‘是球员出生的年份

'igraci‘是一个玩家列表。

程序首先询问你想要输入的玩家数量,然后要求你输入他们的详细信息,并打印出你输入的内容。

代码语言:javascript
运行
复制
#include <stdio.h>

struct futbaler
    {
        char ime[15];
        char prezime[20];
        char pozicija[15];
        char godiste[4];
    };

void upis(struct futbaler* pok, int n)
{
    int i;

    for(i=0; i<n;i++)
    {
        printf("Ime igraca #%d: ",i+1);
        scanf("%s",(pok+i)->ime);
        printf("Prezime igraca #%d: ",i+1);
        scanf("%s",(pok+i)->prezime);
        printf("Pozicija igraca #%d: ",i+1);
        scanf("%s",(pok+i)->pozicija);
        printf("Godiste igraca #%d: ",i+1);
        scanf("%s",(pok+i)->godiste);
    }
}

void ispis(struct futbaler* pok, int n)
{
    int i;

    for(i=0; i<n;i++)
    {
        printf("\nIme igraca #%d je: %s\n",i+1,(*(pok+i)).ime);
        printf("\nPrezime igraca #%d je: %s\n",i+1,(*(pok+i)).prezime);
        printf("\nPozicija igraca #%d je: %s\n",i+1,(*(pok+i)).pozicija);
        printf("\nGodiste igraca #%d je: %s\n",i+1,(*(pok+i)).godiste);
    }
}

main()
{
    int n;
    printf("Koliko bi igraca uneli? ");
    scanf("%d",&n);
    struct futbaler* pok;
    struct futbaler igraci[n];
    pok = igraci;
    upis(pok,n);
    ispis(pok,n);

    printf("%s",igraci[0].godiste);
}

我只是想弄清楚为什么以及如何将这些与彼此无关的值附加在一起。

EN

回答 1

Stack Overflow用户

发布于 2019-05-23 12:48:28

由David C. Rankin指出的更正编辑。

编译器需要在编译时知道数组的长度,以便知道在堆栈上分配多少内存。否则,如果您现在这样做,通过询问用户要制作多大的数组,然后堆栈分配它,您就使用了一种称为可变长度数组(VLA)的特性。出于安全原因,这不是一个好主意。

话虽如此,您的问题似乎源于您的年份字段是一个四字符数组。字符数组是C中的字符串,按照惯例,它们必须以nul结尾,以指示它们的终止位置。由于您在一个只能包含四个字符的空格中编写了一个四个字符的值(年份),因此结果是程序实际上并没有将第一个元素分配给前一个元素的最后一个;实际发生的情况是,当它读取结构的最后一个字段时,它没有找到nul结束符并直接读取它。因此,数组是一个连续的内存块,因此它将这两个字段视为一个字段。

最后,我强烈建议您使用更传统的方法取消对数组的引用。arr[i]只是*(arr + i)的语法糖,但它更容易阅读。不是说这是问题的根源,但任何能让你的生活变得更容易的事情都可能是一个好主意。

这是我对你的问题的实现。

代码语言:javascript
运行
复制
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>

#ifndef TRUE
enum { FALSE= 0, TRUE = !FALSE };
#endif

#define MAX_LINE_LENGTH 80

/* munch: remove newline from input buffer */
void munch(char* s) {
    size_t len = strlen(s);

    for (size_t i = len - 1; i >= 0; --i) {
        if (s[i] == '\n') {
            s[i] = '\0';
            break;
        }
    }
}

void strcpy_(char* s, const char* t) {
    while ((*s++ = *t++) != '\0')
        ;
}

char* strdup_(const char* s) {
    size_t len = strlen(s);
    char* str = malloc((len + 1) * sizeof (char));

    if (str == NULL) {
        fprintf(stderr, "[Error] Memory allocation failure\n");

        exit(EXIT_FAILURE);
    }

    return memcpy(str, s, len + 1);
}

enum position_t {
    POSITION_UNDEFINED,
    POSITION_STRIKER,
    POSITION_MIDFIELDER,
    POSITION_DEFENDER,
    POSITION_GOALKEEPER
};

const char* position_striker_strings[] = {
    "Striker",
    "striker",
    "False 9",
    "false 9"
};

const char* position_midfielder_strings[] = {
    "Midfielder",
    "midfielder",
    "Centerback",
    "centerback"
};

const char* position_defender_strings[] = {
    "Defender",
    "defender",
    "Fullback",
    "fullback"
};

const char* position_goalkeeper_strings[] = {
    "Goalkeeper",
    "goalkeeper",
    "Goalie",
    "goalie"
};

int position_read(const char* s) {
    for (size_t i = 0; i < (sizeof (position_striker_strings) / sizeof(const char*)); ++i) {
        if (strcmp(s, position_striker_strings[i]) == 0)
            return POSITION_STRIKER;
    }

    for (size_t i = 0; i < (sizeof (position_midfielder_strings) / sizeof(const char*)); ++i) {
        if (strcmp(s, position_midfielder_strings[i]) == 0)
            return POSITION_MIDFIELDER;
    }

    for (size_t i = 0; i < (sizeof (position_defender_strings) / sizeof(const char*)); ++i) {
        if (strcmp(s, position_defender_strings[i]) == 0)
            return POSITION_DEFENDER;
    }

    for (size_t i = 0; i < (sizeof (position_goalkeeper_strings) / sizeof(const char*)); ++i) {
        if (strcmp(s, position_goalkeeper_strings[i]) == 0)
            return POSITION_GOALKEEPER;
    }

    return POSITION_UNDEFINED;
}

char* position_str(int position) {
    switch (position) {
        case POSITION_STRIKER: {
            return "Striker";
        } break;

        case POSITION_MIDFIELDER: {
            return "Midfielder";
        } break;

        case POSITION_DEFENDER: {
            return "Defender";
        } break;

        case POSITION_GOALKEEPER: {
            return "Goalkeeper";
        } break;

        default: {
            return "Unknown Position Code";
        }
    }
}

struct player_t {
    char* first_name;
    char* last_name;
    int position;
    int year;
};

struct player_t* player_allocate() {
    struct player_t* player = calloc(1, sizeof(struct player_t));

    if (player == NULL) {
        fprintf(stderr, "[Error] Memory allocation failure\n");

        exit(EXIT_FAILURE);
    }

    return player;
}

struct player_t* player_new(const char* first_name, const char* last_name, int position, int year) {
    struct player_t* p = player_allocate();

    p->first_name = strdup_(first_name);
    p->last_name = strdup_(last_name);
    p->position = position;
    p->year = year;

    return p;
}

void player_print(struct player_t* player) {
    if (player == NULL)
        return;

    printf("\t%s, %s\n", player->last_name, player->first_name);
    printf("\t\tPosition: %s\n", position_str(player->position));
    printf("\t\tYear: %d\n", player->year);
}

void player_list_print(struct player_t** player_list, size_t n) {
    if (player_list == NULL)
        return;

    printf("\n\nPlayer List: \n\n");

    for (size_t i = 0; i < n; ++i) {
        if (player_list[i] == NULL)
            continue;

        player_print(player_list[i]);
    }

    printf("\n\n");
}

void clear_buffer(char* buffer, size_t n) {
    memset(buffer, 0, n * sizeof(char));
}

int main(void)
{
    char input_buffer[MAX_LINE_LENGTH];
    clear_buffer(input_buffer, MAX_LINE_LENGTH);

    printf("How many players would you like to enter? ");
    fgets(input_buffer, MAX_LINE_LENGTH, stdin);

    errno = 0;
    char* endptr = NULL;
    long n = strtol(input_buffer, &endptr, 10);

    if ((errno == ERANGE && (n == LONG_MAX || n == LONG_MIN)) || (errno != 0 && n == 0)) {
        perror("strtol");

        return EXIT_FAILURE;
    }

    if (endptr == input_buffer) {
        fprintf(stderr, "No digits were found\n");

        return EXIT_FAILURE;
    }

    printf("Enter %ld player(s).\n", n);

    struct player_t** player_list = calloc(n, sizeof (struct player_t *));

    for (size_t i = 0; i < (size_t) n; ++i) {
        player_list[i] = player_allocate();

        printf("\nFirst Name: ");
        clear_buffer(input_buffer, MAX_LINE_LENGTH);
        fgets(input_buffer, MAX_LINE_LENGTH, stdin);
        munch(input_buffer);
        player_list[i]->first_name = strdup_(input_buffer);

        printf("Last Name: ");
        clear_buffer(input_buffer, MAX_LINE_LENGTH);
        fgets(input_buffer, MAX_LINE_LENGTH, stdin);
        munch(input_buffer);
        player_list[i]->last_name = strdup_(input_buffer);

        printf("Position: ");
        clear_buffer(input_buffer, MAX_LINE_LENGTH);
        fgets(input_buffer, MAX_LINE_LENGTH, stdin);
        munch(input_buffer);
        player_list[i]->position = position_read(strdup_(input_buffer));

        printf("Year: ");
        clear_buffer(input_buffer, MAX_LINE_LENGTH);
        fgets(input_buffer, MAX_LINE_LENGTH, stdin);
        munch(input_buffer);
        player_list[i]->year = atoi(input_buffer);
    }

    player_list_print(player_list, n);

    return EXIT_SUCCESS;
}

程序执行:

代码语言:javascript
运行
复制
How many players would you like to enter? 2
Enter 2 player(s).

First Name: Christiano 
Last Name: Ronaldo
Position: Striker
Year: 1985

First Name: Lionel
Last Name: Messi
Position: striker
Year: 1986


Player List: 

    Ronaldo, Christiano
        Position: Striker
        Year: 1985
    Messi, Lionel
        Position: Striker
        Year: 1986

您会注意到,我编写了自己的strdup_strcpy_函数。我想看看它们是如何实现的会很有趣,我还为许多换行符和制表符添加了一些功能。这是因为我不喜欢使用scanf,所以我在这个示例中同时包含了atoistrtol的使用。

您还会注意到,strtol涉及到很多错误检查,而atoi没有;这正是using atoi is not recommended的原因。

关于实现,因为列表中的球员数量在编译时是不确定的,所以我使用了一个名为player_list的双指针来动态分配每个球员。为此,您必须首先分配player_list指针本身,然后遍历每个指针,依次单独分配每个播放器结构。

我还对位置使用了整数值,对有效的位置值使用了枚举。在读取用户输入时,我会检查有效的位置字符串是否匹配,如果确实存在匹配,则只添加特定位置。这是为了数据验证目的,因此用户不能简单地添加新职位;这将是数据库管理员的工作。相反,如果未找到匹配项,则将播放器位置简单地设置为POSITION_UNDEFINED

有效位置字符串的数量是根据数组中的位置数来计算的,因此您可以自由地在每个位置数组中添加更多有效字符串,而不必担心更改位置字符串匹配代码。

如果你只是想要一个基本的实现,你可以稍微修改你的代码来处理年份/终止符的问题,也许还可以把name字段改成指针来处理任何大小的名字。就目前而言,您很容易受到堆栈溢出的攻击。我没有仔细研究您的输入机制,但我非常确定您的输入中应该有多余的换行符,因为在调用scanf之后,输入缓冲区中会有换行符。可能会有什么值得注意的地方。

希望这能帮上忙,伙计。我翻译了你代码中的名字,如果谷歌翻译是正确的,它是克罗地亚语。如果这是真的,那么恭喜你去年进入了决赛。祝好运

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56261333

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档