这是我的顶级 cmets 的序言。
永远不要使用goto。使用(例如)while 循环。
menu 的 scanf [可能] 会溢出。
正如其他人所提到的,存在许多错误。
我已经用您的旧代码和一些新代码重构了您的代码。这仍然需要更多的错误检查,并且可以更概括一点,但是,我已经测试了它的基本功能:
#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;
}