【问题标题】:C Void ending issueC 无效结尾问题
【发布时间】:2020-04-12 22:32:55
【问题描述】:

我正在尝试编写一个简单的停车安排代码,我想按 1000 辆车、颜色、车牌和型号对容量进行排序

#include <stdio.h>
#include <stdlib.h>
void NewCar()
{
    char model[1000][20];
    char color [1000][20];
    char number[1000][20];
    int x = 1;
        printf("\nModel: ");
        scanf("%s",model[x]);
        printf("Color: ");
        scanf("%s",color[x]);
        printf("Number: ");
        scanf("%s",number[x]);
}
void CarList()
{
    int x;
    char model[1000][20];
    char color [1000][20];
    char number[1000][20];
    for (x ; x >= 1 ; x--)
    {
        printf("\n%d. Car: %s %s %s",x,number[x],model[x],color[x]);
    }
}
int main()
{
    char model[1000][20];
    char color [1000][20];
    char number[1000][20];
    char menu;
    int x = 1;
    flag:
    printf("New Car(N)\nCar List(L)\n");
    scanf("%s",&menu);
    if (menu == "n" || menu == "N")
    {
        NewCar();
        goto flag;
    }
    if (menu == "l" || menu == "L")
    {
        CarList();
        goto flag;
    }
}

当我不使用 void 时,代码可以工作,但我必须使用 void

我想要的输出示例;

 1. Car Red Jeep FGX9425
 2. Car Yellow Truck OKT2637
 3. Car Green Sedan ADG4567
 ....

【问题讨论】:

  • 您所说的“使用 void”究竟是什么意思?什么不起作用?以什么方式?你的问题很不清楚。
  • 请不要使用goto 代替循环。这是一个非常糟糕的主意
  • @UnholySheep 这还不错。在这种特殊情况下(状态机),它甚至可能是最清晰的。
  • scanf("%s",&amp;menu); 非常错误,因为menu 是单个char,因此除了空字符串之外不能存储任何字符串。可能打算改用%c
  • 这段代码中有很多与void无关的问题,例如:scanf("%s",&amp;menu);是错误的,因为menu是单个charif (menu == "n" || menu == "N")不是你比较字符串的方式在 C 中(你可以使用 strcmp

标签: c void


【解决方案1】:

这是我的顶级 cmets 的序言。

永远不要使用goto。使用(例如)while 循环。

menuscanf [可能] 会溢出。

正如其他人所提到的,存在许多错误。

我已经用您的旧代码和一些新代码重构了您的代码。这仍然需要更多的错误检查,并且可以更概括一点,但是,我已经测试了它的基本功能:

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

// description of a car
struct car {
    char model[20];
    char color[20];
    char number[20];
};

int
NewCar(struct car *cars,int carcount)
{
    struct car *car = &cars[carcount];

    printf("\nModel: ");
    scanf("%s", car->model);

    printf("\nColor: ");
    scanf("%s", car->color);

    printf("\nNumber: ");
    scanf("%s", car->number);

    ++carcount;

    return carcount;
}

void
CarList(struct car *cars,int carcount)
{
    struct car *car;
    int caridx;

    for (caridx = 0;  caridx < carcount;  ++caridx) {
        car = &cars[caridx];
        printf("%d. Car: %s %s %s\n",
            caridx + 1, car->number, car->model, car->color);
    }
}

int
main(int argc,char **argv)
{
#if 1
    int carcount = 0;
    struct car carlist[1000];
#endif
#if 0
    char menu;
    int x = 1;
#else
    char menu[20];
#endif

    // force out prompts
    setbuf(stdout,NULL);

    while (1) {
        printf("New Car(N)\nCar List(L)\n");
#if 0
        scanf("%s", &menu);
#else
        scanf(" %s", menu);
#endif

        // stop program
        if ((menu[0] == 'q') || (menu[0] == 'Q'))
            break;

        switch (menu[0]) {
        case 'n':
        case 'N':
            carcount = NewCar(carlist,carcount);
            break;

        case 'l':
        case 'L':
            CarList(carlist,carcount);
            break;
        }
    }

    return 0;
}

更新:

如你所说,有一些小错误,对我来说不是问题,但如果你想知道并修复它们,我可以写错误。(如果你写的板块之间有空格,代码会重复“新车汽车清单”命令多次)

好的,我制作了一个增强版本,它用一个使用fgets 的函数askfor 替换了scanf。后者将防止 [意外] 缓冲区溢出。而且,混合scanf fgets 可能会有问题。就个人而言,我总是使用fgets“自己动手”,因为它可以提供更精细的粒度控制[如果与包装函数一起使用,例如此处提供的askfor]

编辑:根据 chux,我已将用于删除换行符的 strlen 替换为使用 strchr 的更安全版本:

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

#define STRMAX      20

// description of a car
struct car {
    char model[STRMAX];
    char color[STRMAX];
    char number[STRMAX];
};

// askfor -- ask user for something
void
askfor(const char *tag,char *ptr)
{

    printf("Enter %s: ",tag);
    fflush(stdout);

    fgets(ptr,STRMAX,stdin);

    // point to last char in buffer
    // remove newline
#if 0
    ptr += strlen(ptr);
    --ptr;
    if (*ptr == '\n')
        *ptr = 0;
#else
    // remove trailing newline [if it exists]
    ptr = strchr(ptr,'\n');
    if (ptr != NULL)
        *ptr = 0;
#endif
}

int
NewCar(struct car *cars,int carcount)
{
    struct car *car = &cars[carcount];

    askfor("Model",car->model);
    askfor("Color",car->color);
    askfor("Number",car->number);

    ++carcount;

    return carcount;
}

void
CarList(struct car *cars,int carcount)
{
    struct car *car;
    int caridx;

    for (caridx = 0;  caridx < carcount;  ++caridx) {
        car = &cars[caridx];
        printf("%d. Car: %s %s %s\n",
            caridx + 1, car->number, car->model, car->color);
    }
}

int
main(int argc,char **argv)
{
    int carcount = 0;
    struct car carlist[1000];
    char menu[STRMAX];

    // force out prompts
    setbuf(stdout,NULL);

    while (1) {
        askfor("\nNew Car(N)\nCar List(L)",menu);

        // stop program
        if ((menu[0] == 'q') || (menu[0] == 'Q'))
            break;

        switch (menu[0]) {
        case 'n':
        case 'N':
            carcount = NewCar(carlist,carcount);
            break;

        case 'l':
        case 'L':
            CarList(carlist,carcount);
            break;
        }
    }

    return 0;
}

更新 #2:

感谢您修复错误,但正如我在问题中所说,我必须使用 void 执行“新车”功能。你用int做的,你能用void做吗?

好的。当您说“使用 void”时,您的意思对我 [或其他一些人] 并不完全清楚。有足够多的错误,它们掩盖了其他一些考虑因素。

所以,我不得不假设“使用 void”意味着函数返回 void

您的原始函数被定义为void NewCar()void CarList()。那些无法按原样完成工作,因此必须进行更改。

如果您有类似的标准,更好的表达方式是:

我必须创建两个函数,具有以下函数签名...

无论如何,这是更新后的代码:

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

#define STRMAX      20

// description of a car
struct car {
    char model[STRMAX];
    char color[STRMAX];
    char number[STRMAX];
};

// askfor -- ask user for something
void
askfor(const char *tag,char *ptr)
{

    printf("Enter %s: ",tag);
    fflush(stdout);

    fgets(ptr,STRMAX,stdin);

    // remove trailing newline [if it exists]
    ptr = strchr(ptr,'\n');
    if (ptr != NULL)
        *ptr = 0;
}

void
NewCar(struct car *cars,int *countptr)
{
    int carcount = *countptr;
    struct car *car = &cars[carcount];

    askfor("Model",car->model);
    askfor("Color",car->color);
    askfor("Number",car->number);

    carcount += 1;
    *countptr = carcount;
}

void
CarList(struct car *cars,int carcount)
{
    struct car *car;
    int caridx;

    for (caridx = 0;  caridx < carcount;  ++caridx) {
        car = &cars[caridx];
        printf("%d. Car: %s %s %s\n",
            caridx + 1, car->number, car->model, car->color);
    }
}

int
main(int argc,char **argv)
{
    int carcount = 0;
    struct car carlist[1000];
    char menu[STRMAX];

    // force out prompts
    setbuf(stdout,NULL);

    while (1) {
        askfor("\nNew Car(N)\nCar List(L)",menu);

        // stop program
        if ((menu[0] == 'q') || (menu[0] == 'Q'))
            break;

        switch (menu[0]) {
        case 'n':
        case 'N':
#if 0
            carcount = NewCar(carlist,carcount);
#else
            NewCar(carlist,&carcount);
#endif
            break;

        case 'l':
        case 'L':
            CarList(carlist,carcount);
            break;
        }
    }

    return 0;
}

但是,鉴于您的原始函数,签名可能是:void NewCar(void)void CarList(void),并且汽车列表变量必须是全局 范围。

这将是一种不太灵活和理想的做事方式,但这里有一个仅使用全局变量作为列表的版本:

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

#define STRMAX      20

// description of a car
struct car {
    char model[STRMAX];
    char color[STRMAX];
    char number[STRMAX];
};

#if 1
int carcount = 0;
struct car carlist[1000];
#endif

// askfor -- ask user for something
void
askfor(const char *tag,char *ptr)
{

    printf("Enter %s: ",tag);
    fflush(stdout);

    fgets(ptr,STRMAX,stdin);

    // remove trailing newline [if it exists]
    ptr = strchr(ptr,'\n');
    if (ptr != NULL)
        *ptr = 0;
}

void
NewCar(void)
{
    struct car *car = &carlist[carcount];

    askfor("Model",car->model);
    askfor("Color",car->color);
    askfor("Number",car->number);

    carcount += 1;
}

void
CarList(void)
{
    struct car *car;
    int caridx;

    for (caridx = 0;  caridx < carcount;  ++caridx) {
        car = &carlist[caridx];
        printf("%d. Car: %s %s %s\n",
            caridx + 1, car->number, car->model, car->color);
    }
}

int
main(int argc,char **argv)
{
#if 0
    int carcount = 0;
    struct car carlist[1000];
#endif
    char menu[STRMAX];

    // force out prompts
    setbuf(stdout,NULL);

    while (1) {
        askfor("\nNew Car(N)\nCar List(L)",menu);

        // stop program
        if ((menu[0] == 'q') || (menu[0] == 'Q'))
            break;

        switch (menu[0]) {
        case 'n':
        case 'N':
#if 0
            carcount = NewCar(carlist,carcount);
#else
            NewCar();
#endif
            break;

        case 'l':
        case 'L':
#if 0
            CarList(carlist,carcount);
#else
            CarList();
#endif
            break;
        }
    }

    return 0;
}

【讨论】:

  • 非常感谢您的回答,我标记为正确答案
  • 不客气。您也可以将其“投票”为“好”的答案(并且可以投票给其他可能出现的答案)。祝你好运。顺便说一句,struct非常强大的,所以值得研究一下。
  • 如你所说,有一些小错误,对我来说不是问题,但如果你想知道并修复它们,我可以写错误。(如果你写的盘子之间有空格它,代码多次重复“新车汽车列表”命令)
  • scanf(" %s", menu);gets() 一样好。建议限制宽度。 ``scanf("%19s", menu);`
  • @chux-ReinstateMonica 做了第二个代码示例,将scanf 替换为fgets,用于防止缓冲区溢出和获取整行字符串。我不是scanf("%19s",menu) 的粉丝,我为scanf 尝试了类似于int max = 19; printf("%*s\n",max,menu); 的东西:int max = sizeof(menu) - 1; scanf("%*s",max,menu);,但它没有用。 scanf 有这样的等价物吗?我正在寻找的东西不是:stackoverflow.com/questions/25410690/… 或使用m 说明符[因为它做了额外/隐藏的malloc]
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-19
  • 1970-01-01
  • 2019-09-07
相关资源
最近更新 更多