我正在解决一个保留商店库存证据的问题,有一个部分要求获取产品代码,我必须通过反转产品名称来获取该代码。
例如:
name of the product : snack
codebar: kcans
一切都工作得很好,直到到达
strcpy
线。
菜单不是英文的,但第一个菜单获取输入,第二个菜单将显示输出。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Product
{
char productName[30];
char productCode[30];
int price;
int stock;
int date[3];
}P;
char* reverse(char *name)
{
char aux[30];
int i,j;
for(i = strlen(name) - 1, j = 0; i >= 0; i--,j++)
{
aux[j] = name[i];
}
aux[j] = '\0';
return aux[30];
}
int nameValidation(char *name)
{
int i;
for(i = 0; i < strlen(name); i++)
{
if(name[i] >= 'a' && name[i] <= 'z');
else
{
return 0;
break;
}
}
if(i == strlen(name))
return 1;
}
void input(P *product, int *n)
{
(*n)++;
do
{
printf("Product name: ");
scanf("%s", (product + *n)->productName);
} while (!nameValidation((product + *n)->productName));
printf("Price: ");
scanf("%d", &(product + *n)->price);
printf("Quantity: ");
scanf("%d", &(product + *n)->sotck);
do
{
printf("Expiration day: ");
scanf("%d", &(product + *n)->date[0]);
if((product + *n)->date[0] >= 1 && (product + *n)->date[0] <= 30)
break;
} while (1);
do
{
printf("Expiration month: ");
scanf("%d", &(product + *n)->date[1]);
if((product + *n)->date[1] >= 1 && (product + *n)->date[1] <= 12)
break;
} while (1);
(product + *n)->date[2] = 2024;
printf("Expiration Year: %d\n", (product + *n)->date[2]);
strcpy((product + *n)->productCode, reverse((product + *n)->productName));
printf("Product Code: %5s\n", (product + *n)->productCode);
}
void output(P *product, int n)
{
int i;
for(i = 0; i <= n; i++)
{
printf("Product name: %10s ", (product + i)->productName);
printf("Price: %5d ", (product + i)->price);
printf("Stock:%5d\n", (product + i)->stock);
}
}
int main()
{
int option;
int n;
P product[100];
n = -1;
do
{
printf("\n0.Iesire\n");
printf("1.Citirea unui produs de la tastatura\n");
printf("2.Afisarea produselor citite\n");
printf("3.Afisarea produselor cu un pret mai mic dat de utilizator\n");
printf("4.Sa se afiseze toate produsele care au lungimea numelui egala cu un numar par\n");
printf("5.Afisarea primului produs care este egal cu un nume dat de utilizator\n");
printf("6.Sa se realizeze produsul cifrelor fiecarui numar de bucati al produselor, apoi sa se copieze fiecare produs intr-un vector si sa se afiseze vectorul.\n");
printf("7.Copierea tuturor codurilor produselor intr-un vector de sir de caractere, apoi afisare vectorului\n");
printf("8.Copierea pretului produselor intr-un vector apoi afisarea vectorului in ordine crescatoare\n");
printf("9.Sa se transforme prima litera din codul produsului in litera mare daca aceasta este vocala.Nu se vor folosii functii predefinite in schimbarea literei\n");
printf("10.Sa se afiseze forma binara a numarului de bucati ale produselor care au numarul de bucati mai mic decat 100 .\n");
printf("11.Sa se afiseze toate produsele care urmeaza sa expire in urmatoarele 10 zile.Utilizator va preciza de la tastatura ziua si luna curenta.\n");
printf("12.Sa se pun pe ultimul rand al unei matrici de caractere de ordin dat de numarul de produse, primul caracter din fieacre nume de produs,pe restul '.'\n");
printf("13.Stabilirea unui nou pret pt toate produsele daca utilizatorul doreste.Astfel utilizator va stabili procentajul cu care se vor scumpi produsele.\n");
printf("14.Sa se stearga un produs precizat de utilizator prin numele acestuia\n");
printf("Introduceti o optiune: ");
scanf("%d", &optiune);
switch (option)
{
case 1:
input(product, &n);
break;
case 2:
output(product, n);
break;
case 3:
break;
case 4:
/* code */
break;
case 5:
/* code */
break;
case 6:
/* code */
break;
case 7:
/* code */
break;
case 8:
/* code */
break;
case 9:
/* code */
break;
case 10:
/* code */
break;
case 11:
/* code */
break;
case 12:
/* code */
break;
case 13:
/* code */
break;
case 14:
/* code */
break;
case 0:
exit(1);
break;
default:
printf("Introduceti o optiune valida");
break;
}
} while (option != 0);
return 0;
}
我发布了原始代码的公认“代码转储”修订版(带有少量注释),以演示“大局”草图如何与增量开发共存。请从
main()
的入口点到exit()
的case 0:
来研究这个例子。请注意较短的名称如何“阐明”函数中代码的作用。当您想“复制/粘贴/改编”某些代码行时,问问自己是否可以通过分解一个单独的函数来更好地实现该功能。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Product {
char name[30]; // meaningful but shorter name
char code[30]; // meaningful but shorter name
int price;
int stock;
int exp_yr, exp_mo, exp_dy; // no confusion
} P_t; // conventional to use "_t" with tokens 'typedef'd
// primative 'helper' functions
char *getString( char *prompt, char *to, int len ) {
printf( "%s", prompt );
fgets( to, len, stdin );
to[ strlen(to) - 1 ] = '\0'; // get rid of '\n'
return to;
}
int getInt( char *prompt ) {
char buf[32];
return atoi( getString( prompt, buf, sizeof buf ) );
}
char *reverse( char *str ) { // "in place" string reversal
int lft = 0;
int rgt = strlen( str ) - 1;
for( ; lft <= rgt; lft++, rgt-- ) {
char tmp = str[ lft ];
str[ lft ] = str[ rgt ];
str[ rgt ] = tmp;
}
return str;
}
int nameValid( char *str ) { // check for bad chars
if( *str == '\0' ) return 0; // At least one char required
char *permitted = "- abcdefghijklmnopqrstuvwxyz"; // extra acceptable chars
return strspn( str, permitted ) == strlen( str ); // true if all chars okay
}
void input( P_t *pp ) { // fill-in ONE record
do {
getString( "Product name: ", pp->name, sizeof pp->name );
} while( !nameValid( pp->name ) );
reverse( strcpy( pp->code, pp->name ) );
printf( "Product Code: %s\n", pp->code );
pp->price = getInt( "Price: " );
pp->stock = getInt( "In stock: " );
// Not good, but sufficient
while( ( pp->exp_dy = getInt( "Exp. day: " ) ) < 1 || pp->exp_dy > 31 ) {} // loop
while( ( pp->exp_mo = getInt( "Exp. month: " ) ) < 1 || pp->exp_mo > 12 ) {} // loop
pp->exp_yr = getInt( "Exp. year: " );
}
// Renamed to show outputs multiple records
// Equivalent, but easier to think of as array
void outputAll( P_t prod[], int n ) {
for( int i = 0; i < n; i++ ) { // NB: changed '<=' to '<'
P_t *pp = &prod[ i ]; // less verbose
printf( "Product name: %10s ", pp->name );
printf( "Price: %5d ", pp->price );
printf( "Stock:%5d", pp->stock );
printf( "\n" ); // Clearly 'end of line'
}
}
int main() {
P_t product[100]; // uninitialised
int count = 0;
memset( product, 0, sizeof product ); // Now initialised
for( ;; ) {
printf(
"\n0.Iesire\n" );
printf(
"1.Citirea unui produs de la tastatura\n" );
printf(
"2.Afisarea produselor citite\n" );
/* printf(
"3.Afisarea produselor cu un pret mai mic dat de utilizator\n" );
printf(
"4.Sa se afiseze toate produsele care au lungimea numelui egala cu un numar par\n" );
printf(
"5.Afisarea primului produs care este egal cu un nume dat de utilizator\n" );
printf(
"6.Sa se realizeze produsul cifrelor fiecarui numar de bucati al produselor, "
"apoi sa se copieze fiecare produs intr-un vector si sa se afiseze vectorul.\n" );
printf(
"7.Copierea tuturor codurilor produselor intr-un vector de sir de caractere, "
"apoi afisare vectorului\n" );
printf(
"8.Copierea pretului produselor intr-un vector "
"apoi afisarea vectorului in ordine crescatoare\n" );
printf(
"9.Sa se transforme prima litera din codul "
"produsului in litera mare daca aceasta este vocala. "
"Nu se vor folosii functii predefinite in schimbarea literei\n" );
printf(
"10.Sa se afiseze forma binara a numarului de bucati "
"ale produselor care au numarul de bucati mai mic decat 100 .\n" );
printf(
"11.Sa se afiseze toate produsele care urmeaza sa expire in urmatoarele 10 zile. "
"Utilizator va preciza de la tastatura ziua si luna curenta.\n" );
printf(
"12.Sa se pun pe ultimul rand al unei matrici de caractere de ordin "
"dat de numarul de produse, primul caracter "
"din fieacre nume de produs,pe restul '.'\n" );
printf(
"13.Stabilirea unui nou pret pt toate produsele daca utilizatorul "
"doreste.Astfel utilizator va stabili procentajul cu "
"care se vor scumpi produsele.\n" );
printf(
"14.Sa se stearga un produs precizat de utilizator prin numele acestuia\n" );
*/
switch ( getInt( "Introduceti o optiune: " ) ) {
case 0:
exit( 1 ); // Would 'return 0' be better?
break;
case 1:
// increment it here, instead of using pointer there.
// pass only one element to be filled in.
input( &product[ count++ ] );
break;
case 2:
outputAll( product, count );
break;
// ToDo:
// case 3: break;
// case 4: break;
// case 5: break;
// case 6: break;
// case 7: break;
// case 8: break;
// case 9: break;
// case 10: break;
// case 11: break;
// case 12: break;
// case 13: break;
// case 14: break;
// End ToDo
default:
printf("Introduceti o optiune valida");
break;
}
}
return 0;
}
您不应该浪费时间输入 15 个“提示”和 15 个案例标签,就好像添加更多代码就能让事情正常运行一样。我强烈建议删除该代码(或注释掉这些行)并将您的注意力集中在您需要构建的微小实用程序部分上。
不要让编译器仔细研究设计中“待完成”方面的框架代码,我建议注意类似这样的提醒:
// TBD: procedure to wash breakfast dishes
// TBD: plan route and transport to office
// TBD: sell soul for 9 hours in exchange for meager crusts of bread
// TBD: return home to reminisce about wasted but pleasure filled youth
编译器省去了解析和评估仅表达您的良好意图的实际代码的毫无意义的工作。
这是
reverse()
的“固定”版本,可以帮助您继续。请循序渐进地工作,测试添加的每一个微小的额外代码行、所做的每一个微小的更改。山不是从上往下生长的...
char *reverse( char *str ) {
for( int i = 0, j = strlen( str ) - 1; i <= j; i++, j-- ) {
char tmp = str[i];
str[i] = str[j];
str[j] = tmp;
}
return str;
}
int main() {
char *str[] = { "the fish", "goats are good" };
printf( "%s", str[0] );
printf( " == %s\n", reverse( str[0] ) );
printf( "%s", str[1] );
printf( " == %s\n", reverse( str[1] ) );
return 0;
}
输出:
the fish == hsif eht
goats are good == doog era staog
因为此函数“就地”反转字符串,所以您需要调整现有行:
strcpy( (product + *n)->productCode, reverse((product + *n)->productName) );
到
reverse( strcpy( (product + *n)->productCode, (product + *n)->productName) );
(即按顺序执行操作应该是不言而喻的。)