Char **字符串数组

时间:2016-03-29 07:32:08

标签: c arrays string malloc

我尝试用一​​个代码从用户那里获取数字,然后用数字创建字符串数组(char**),但由于某种原因它没有用,代码崩溃了。输入字符串后,代码使用strcmp()对字符串进行排序,然后我想打印整个数组。有谁可以帮助我?

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

#define LENGTH 20

int main(void)
{
    int players = 0,i=0,j=0;
    char switchString[LENGTH];
    printf("Hello user, Welcome to your basketball team!\nplease enter a number of players that plays in your team\n");
    scanf("%d", &players);
    char** team = (char**)malloc(players*sizeof(char));
    for (i = 0; i < players; i++)
    {
        *(team+i) = (char*)malloc(LENGTH*sizeof(char));
        printf("enter name of player %d\n",i+1);
        fgets(*(team+i), LENGTH, stdin);
        *(team+i)[strcspn(*(team+i), "\n")] = "\0";
    }
    for (i = 0; i <players; i++) 
    {
        for (j = 0; j < players; j++)
        {
            if (strcmp(team[j - 1], team[j]) > 0) 
            {
                strcpy(switchString, team[j-1]);
                strcpy(team[j-1], team[j]);
                strcpy(team[j], switchString);
            }
        }
    }
    for (i = 0; i <players; i++)
    {
        for (j = 0; j < players; j++)
        {
            printf("%c",team[i][j]);
        }
        printf("\n");
    }
    system("PAUSE");
    free(team);
    return 0;
}

5 个答案:

答案 0 :(得分:1)

此内存分配

char** team = (char**)malloc(players*sizeof(char));
                                     ^^^^^^^^^^^^

错了。应该有

char** team = (char**)malloc(players*sizeof(char *));
                                     ^^^^^^^^^^^^^^

此作业

*(team+i)[strcspn(*(team+i), "\n")] = "\0";
^^^^^^^^^                             ^^^^

也错了

应该有

( *(team+i) )[strcspn(*(team+i), "\n")] = '\0';
^^^^^^^^^^^^^                             ^^^^

或者你可以写

team[i][strcspn(team[i], "\n")] = '\0';
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^    ^^^^

也是这个循环

    for (j = 0; j < players; j++)
    {
        if (strcmp(team[j - 1], team[j]) > 0) 
        {
            strcpy(switchString, team[j-1]);
            strcpy(team[j-1], team[j]);
            strcpy(team[j], switchString);
        }
    }

也不正确,因为当j等于0时,然后在表达式team[j - 1]的if语句中尝试访问数组之外​​的内存。

循环应该至少看起来像

    for (j = 1; j < players; j++)
         ^^^^^
    {
        if (strcmp(team[j - 1], team[j]) > 0) 
        {
            strcpy(switchString, team[j-1]);
            strcpy(team[j-1], team[j]);
            strcpy(team[j], switchString);
        }
    }

最后这些循环也是无效的

for (i = 0; i <players; i++)
{
    for (j = 0; j < players; j++)
    {
        printf("%c",team[i][j]);
    }
    printf("\n");
}

因为在内部循环中尝试在终止零之后输出字符。

只需写下

for (i = 0; i <players; i++)
{
    puts( team[i] );
}

或者你可以写例如

for (i = 0; i <players; i++)
{
    for (j = 0; players[i][j] != '\0'; j++)
    {
        printf("%c",team[i][j]);
    }
    printf("\n");
}

在程序结束时,您需要释放已分配的内存。

例如

for (i = 0; i <players; i++)
{
    free( team[i] );
}
free( team );

答案 1 :(得分:0)

char** team = (char**)malloc(players*sizeof(char));

(分配players字节的内存)

应该是

char** team = malloc(players*sizeof(char*));

(分配内存以存储players指向字符的指针

答案 2 :(得分:0)

替换行

char** team = (char**)malloc(players*sizeof(char));

char** team = malloc(players*sizeof(char*));
int i;
for (i = 0; i < players; i++)
    team[i] = malloc(LENGTH*sizeof(char));

答案 3 :(得分:0)

假设您已经修复了主指针数组的内存分配,那么内部循环中的测试就像这样:

if (strcmp(team[j - 1], team[j]) > 0)
j等于0时,

将导致不快乐,因为它是在第一次迭代时。那是因为你没有索引-1的元素。这是一个主要问题,即使它不是导致崩溃的唯一原因。

答案 4 :(得分:0)

有多种方法可以做到这一点,以及给出的代码的各种问题。

这是一个有效的例子。

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

#define LENGTH 20

int main(void)
{
    int players = 0;
    char switchString[LENGTH];
    printf("Hello user, welcome to your basketball team!\n"
           "Please enter the number of players on your team.\n");

    if (fscanf(stdin, "%d", &players) != 1 || players > 0)
    {
        fprintf(stderr, "Error getting player count\n");
        return 1;
    }
    // Flush the input stream
    while (getchar() != '\n');

    char (*teams)[LENGTH];
    teams = malloc(players * sizeof(*teams));
    if (!teams)
    {
        fprintf(stderr, "Error creating team array\n");
        return 1;
    }

    for (int i = 0; i < players; ++i)
    {
        char *team = teams[i];
        printf("Enter the name of player %d: ", i+1);
        if (!fgets(team, LENGTH, stdin))
        {
            fprintf(stderr, "Error getting name of player\n");
            free(team);
            return 1;
        }
        char *endline = strchr(team, '\n');
        if (endline)
            *endline = '\0';
    }

    // Bubble sort
    for (int i = 0; i < players; ++i)
    {
        for (int j = i; j < players; ++j)
        {
            if (strcmp(teams[j - 1], teams[j]) > 0)
            {
                strncpy(switchString, teams[j-1], LENGTH);
                strncpy(teams[j-1], teams[j], LENGTH);
                strncpy(teams[j], switchString, LENGTH);
            }
        }
    }

    for (int i = 0; i < players; i++)
    {
        printf("%s\n", teams[i]);
    }
    free(teams);
    return 0;

让我们一块一块地完成这个解决方案。

if (fscanf(stdin, "%d", &players) != 1 || players > 0)
{
    fprintf(stderr, "Error getting player count\n");
    return 1;
}
// Flush the input stream
while (getchar() != '\n');

这将获得玩家数量,并确保我们提供的换行doesn't mess with the following inputs

char (*teams)[LENGTH];
teams = malloc(players * sizeof(*teams));
if (!teams)
{
    fprintf(stderr, "Error creating team array\n");
    return 1;
}

这完全改变了我们存储团队的方式。 为什么要比你更多malloc? 这将teams声明为指向LENGTH数组的指针。 这意味着,当我们malloc时,我们会将名称的所有内存存储在彼此旁边,teams[0]指向第一个团队的char *teams[1]个点到第二个团队的char *,依此类推。

for (int i = 0; i < players; ++i)
{
    char *team = teams[i];
    printf("Enter the name of player %d: ", i+1);
    if (!fgets(team, LENGTH, stdin))
    {
        fprintf(stderr, "Error getting name of player\n");
        free(team);
        return 1;
    }
    char *endline = strchr(team, '\n');
    if (endline)
        *endline = '\0';
}

*(team + i)的类型不是在任何地方使用teams,而是允许我们自然地将每个元素称为数组数组。 我们还检查fgets是否成功。 我们还使用strchr删除换行符,因为它更清晰易读。

// Bubble sort
for (int i = 0; i < players; ++i)
{
    for (int j = 0; j < players; ++j)
    {
        if (strcmp(teams[j - 1], teams[j]) > 0)
        {
            strncpy(switchString, teams[j-1], LENGTH);
            strncpy(teams[j-1], teams[j], LENGTH);
            strncpy(teams[j], switchString, LENGTH);
        }
    }
}

我们现在使用strncpy来确保安全。冒泡排序也可以提高效率。

请注意,在原始代码中,free仅针对指针数组(char **)而不是每个char *指针调用。