线程 1:访问错误,如何解决这个问题?

问题描述 投票:0回答:1

当我运行这个短程序时,每次尝试从文件导入数据时,我都会遇到 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 错误

c exc-bad-access
1个回答
0
投票

我怀疑我知道发生了什么事。

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。但您还应该检查匹配和分配的输入项的预期数量,如果不正确则打印错误。

© www.soinside.com 2019 - 2024. All rights reserved.