当我运行这个短程序时,每次尝试从文件导入数据时,我都会遇到 BAD ACCESS 错误,我问我出了什么问题以及我应该做什么来修复它并升级程序,我'抱歉,评论和任务都是意大利语。预先感谢您的帮助。 PS 是的,是 C 语言...
/* Questo programma è scritto per gestire il calendario di una squadra di calcio impegnata in più competizioni,
come esempio viene preso il Manchester City, impegnato in Premier League, FA Cup e Champions League.
Ogni partita presenta i seguenti dati: codice (3 numeri, il primo indica il torneo,
gli atri due il turno o la giornata), avversario, casa (h) o trasferta (a), la data e la giornata che,
in caso di coppa, dalla settima alla decima giornata sono risettivamente ottavi di finale (7), quarti (8),
semifinale(9) e finale (10). Il codice consente di stampare la singola partita cercandola tramite codice.
Il programma consente inoltre di stampare tutto il calendario, aggiungere o rimuovere partite,
riprogrammare le partite di campionato, quindi cambiare loro data. In teoria questa funzionalità
consente di spostare le partite in caso di stop per le nazionali o di successo nelle coppe e quindi
per evitare sovrapposizioni di impegni.
Inoltre FA Cup e Champions League hanno 6 turni che indicheremo come giorata da 1 a 6 prima degli ottavi
di finale. Per facilitare all'utente la funzione di aggiunta non si prende in considerazione
che in champions league ci sono andata e ritorno per ottavi, quarti e semi finale, altrimenti
l'utente avrebbe dovuto aggiungere due partite alla volta. Quando si aggiungono partite, prestare attenzione
alla data, è buona norma, in fase di definizione del calendario, programmare le partite di coppa il mercoledi
e quelle di campionato la domenica, per poi modificarne la fascia oraria e la data specifica solo
in prossimita dell'evento. Infine il programma permettere di importare
da un file un calendario o di salvare il calendario in un file.
*/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAX 20 /* per il nome della squadra avversaria */
/* definisco le strutture dati */
struct partita {
char codice[4];
char * opp;
char casa[5];
int giornata;
char * torneo;
int giorno;
int mese;
int anno;
};
typedef struct partita tPartita;
struct listNode
{
tPartita partita;
struct listNode *nextMatch;
};
typedef struct listNode tNode;
typedef tNode *tList;
/* prototipi delle funzioni necessarie da sviluppare */
void stampaCalendario(tList);
void aggiungiPartita(tPartita *);
void inserisciPartita(tList *, tPartita *);
void modificaPartita(tList ); /* per visualizzare e rimandare la partita cercata */
void stampaPartita(tNode *);
void cancellaPartita(tList *);
void ImportSchedule(tList *, char *);
/* importa il calendario da file */
void SaveSchedule(tList, char *);
/* salva il calendario su un file */
/* PRINCIPALE */
int main(void) {
tList lista = NULL;
tPartita match;
int choice; /* scelta dal menù fornito */
do {
printf("_ Cosa vuoi fare? _\n"
"_ stampa il calendario (1)_\n"
"_ aggiungi una partita (2)_\n"
"_ cancella una partita (3)_\n"
"_ modifica una partita (4)_\n"
"_ importa il calendario (5)_\n"
"_ salva il calendario (6)_\n"
"_ fine (0)_\n");
scanf("%d ", &choice);
switch (choice) {
case 1:
stampaCalendario(lista);
break;
case 2:
aggiungiPartita(&match);
inserisciPartita(&lista, &match);
break;
case 3:
cancellaPartita(&lista);
break;
case 4:
modificaPartita(lista);
break;
case 5:
ImportSchedule(&lista, "dati.txt");
break;
case 6:
SaveSchedule(lista, "dati.txt");
break;
case 0:
printf("_*USCITA DAL PROGRAMMA*_\n");
break;
default:
printf("Non hai fatto niente...\n");
break;
} /* fine switch */
} while (choice != 0); /* fine del ciclo do_while */
printf("\nFIN\n");
return 0;
}
/* FUNZIONI */
void aggiungiPartita(tPartita *pPartita) {
char buffer[100];
int turno, torneo;
char *cod;
printf("Inserisci il codice della partita: ");
scanf("%s", pPartita->codice);
cod = pPartita->codice;
torneo = atoi(cod) / 100;
turno = atoi(cod) % 100;
if (torneo == 0) {
pPartita->torneo = "PremierLeague";
}
else if (torneo == 1) {
pPartita->torneo = "FACup";
}
else if (torneo == 2) {
pPartita->torneo = "ChampionsLeague";
}
pPartita->giornata = turno;
printf("Inserisci l'avversario: ");
scanf("%s", buffer);
pPartita->opp = malloc(sizeof(strlen(buffer) + 1));
strcpy(pPartita->opp, buffer);
printf("Digita 'home' se la partita è in casa, 'away' se in trasferta: ");
scanf("%s", pPartita->casa);
printf("Inserisci la data nel formato GG MM AA: ");
scanf("%d %d %d",
&(pPartita->giorno),
&(pPartita->mese),
&(pPartita->anno));
}
void inserisciPartita(tList *pStart, tPartita *pNewMatch) {
tList pNewNode;
pNewNode = malloc(sizeof(tNode));
if (!pNewNode)
printf("\n!!Impossibile allocare memoria!!\n");
else {
pNewNode->partita = *pNewMatch;
pNewNode->nextMatch = *pStart;
*pStart = pNewNode;
}
}
void stampaPartita(tNode *pNode) {
printf("%-4scontro %s, %-5s%d giornata, %s, %d-%d-%d\n",
pNode->partita.codice,
pNode->partita.opp,
pNode->partita.casa,
pNode->partita.giornata,
pNode->partita.torneo,
pNode->partita.giorno,
pNode->partita.mese,
pNode->partita.anno);
return;
}
void stampaCalendario(tList lista) {
printf("\nCalendario: \n");
while (lista) {
stampaPartita(lista);
lista = lista->nextMatch;
}
}
void cancellaPartita(tList *pList) {
tNode *pApp, *pScorrimento;
char codiceCanc[4];
printf("Inserisci il codice della partita da cancellare: ");
scanf ("%s", codiceCanc);
pScorrimento = *pList; /* at start */
if (strcmp(pScorrimento->partita.codice, codiceCanc) ) {
pApp = pScorrimento;
pScorrimento = pScorrimento->nextMatch;
while (pScorrimento && strcmp(pScorrimento->partita.codice, codiceCanc) ) {
pApp = pScorrimento;
pScorrimento = pScorrimento->nextMatch;
}
if (pScorrimento) {
pApp->nextMatch = pScorrimento->nextMatch;
free(pScorrimento->partita.opp);
free(pScorrimento);
} else
printf("La partita non è in calendario!\n");
}
else {
*pList = pScorrimento->nextMatch;
free(pScorrimento->partita.opp);
free(pScorrimento);
}
}
void modificaPartita(tList lista) {
char search[4];
int scelta;
printf("Inserisci il codice della partita che ti interessa: ");
scanf("%s", search);
while (lista && strcmp(lista->partita.codice, search) ) /* ricerca */
lista = lista->nextMatch;
if (lista) {
do {
printf("MODIFICA MATCH:\n"
"(1)...Visualizza la partita\n"
"(2)...Posticipa la partita\n"
"(0)...Nada màs...\n");
scanf("%d", &scelta);
switch (scelta) {
case 1:
stampaPartita(lista);
break;
case 2:
printf("Al momento la partita è programmata per il %d-%d-%d\n",
lista->partita.giorno, lista->partita.mese, lista->partita.anno);
printf("In che data vuoi spostarla? (GG MM AA)");
scanf("%d %d %d",
&(lista->partita.giorno), &(lista->partita.mese), &(lista->partita.anno));
break;
default:
break;
}
} while(scelta);
}
else
printf("La partita cercata non è in calendario!\n");
}
/* funzione per salvare il calendario su un file */
void SaveSchedule(tList pNode, char *filename) {
FILE *f;
tList app;
f = fopen(filename, "w");
if (f == NULL)
printf("IL FILE NON SI APRE!! \n");
else {
while (pNode) {
app = pNode;
fprintf(f, "%s ", pNode->partita.codice);
fprintf(f, "%s ", pNode->partita.opp);
fprintf(f, "%s ", pNode->partita.casa);
fprintf(f, "%d ", pNode->partita.giornata);
fprintf(f, "%s ", pNode->partita.torneo);
fprintf(f, "%d ", pNode->partita.giorno);
fprintf(f, "%d ", pNode->partita.mese);
fprintf(f, "%d\n", pNode->partita.anno);
pNode = pNode->nextMatch;
free(app->partita.opp);
free(app);
}
printf("Calendario salvato\n");
fclose(f);
}
}
/* importa il calendario da un file */
void ImportSchedule(tList *pList, char *filename) {
FILE *f;
tPartita match;
int res;
char bufferOpp[30];
f = fopen(filename, "r");
if (f)
{
fseek(f, 0, SEEK_SET);
while ( !feof(f) ) {
res = fscanf(f, "%s %s %s %d %s %d %d %d",
match.codice,
bufferOpp,
match.casa,
&match.giornata,
match.torneo,
&match.giorno,
&match.mese,
&match.anno);
if (res != -1) {
match.opp = malloc(sizeof(strlen(bufferOpp) +1) );
strcpy(match.opp, bufferOpp);
inserisciPartita(pList, &match);
}
}
printf("Operazione effettuata con successo.\n");
fclose(f);
}
else
printf("\n!!PROBLEMI IN APERTURA DEL FILE!!\n");
}
不工作,我在线程 1 中运行:BAD ACCESS 错误
我怀疑我知道发生了什么事。
fscanf()
是一个脆弱的函数,很难正确执行。我通过你的导出函数看到每条记录都以换行符终止。但是您的 fscanf()
调用并没有显式地消耗它。我相信输入不同步,这将迅速导致大字符串被读入小缓冲区,从而溢出它们。
根据
fscanf()
的手册页:
正确使用这些函数非常困难,最好使用 fgets(3) 或 getline(3) 读取整行,然后使用 sscanf(3) 或更专业的函数(例如 strtol(3))解析它们。
我强烈同意更改代码以使用
fgets()
和 sscanf()
。
此外,您还可以在
sscanf()
/ fscanf()
格式字符串中包含长度限定符,以避免缓冲区溢出。例如。 “%3s”最多只能读取 3 个字符。 (请注意,它还会以 null 终止分配,这意味着您的缓冲区需要为 4。)
如果您喜欢
fscanf()
,您可以通过以下方式解决问题:
res = fscanf(f, "%s %s %s %d %s %d %d %d%*c",
...
'%*c' 将消耗并丢弃换行符。
最后,我看到您的代码在插入记录之前检查
fscanf()
的返回值是否为 EOF。但您还应该检查匹配和分配的输入项的预期数量,如果不正确则打印错误。