C语言 输出中有两行不应该出现的特殊字符

wgeznvg7  于 2023-06-21  发布在  其他
关注(0)|答案(1)|浏览(112)

我有一个txt,里面有一个这样格式的歌曲列表:
我们会震撼你
皇后
两点零一分
我需要把这些数据放在一个名为“elenco”的列表中,并使用这个结构:

struct elenco{
    char titolo[30];
    char autore[30];
    int durata_in_sec;
    int rips;
    struct elenco *prossima;
};

我试着用fscanf(fp, "%29[^\n]%*c", elenco->autore);存储数据(以此类推),用简单的printf("%s\n", elenco->autore);存储输出,但输出是正确的,直到程序输出两行特殊字符,如下所示:
?w
☻ ☻ ☻ ☻ ☻ ☻h☻(☻(☻(☻(☻ ☻ ☻ ☻ ☻y
这是完整的程序,如果你想检查它

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

struct elenco{
    char titolo[30];
    char autore[30];
    int durata_in_sec;
    int rips;
    struct elenco *prossima;
};

int main()
{
    FILE *fp;
    fp = fopen("musica.txt", "r");
    int i=0;
    int secondi, minuti;
    struct elenco *start = NULL;
    struct elenco *elenco = NULL;
    struct elenco *prec = NULL;
    while (!feof(fp))
    {
        elenco = malloc(sizeof(struct elenco));
        fscanf(fp, "%29[^\n]%*c", elenco->titolo);
        fscanf(fp, "%29[^\n]%*c", elenco->autore);
        fscanf(fp, "%d:%d", &minuti, &secondi);
        elenco->durata_in_sec = minuti*60+secondi;
        elenco->rips=1;
        elenco->prossima = NULL;
        if(i==0)
        {
            start = elenco;
        }
        else
        {
            prec->prossima = elenco;
        }
        prec = elenco;
        i++;
    }
    
    // Stampa
    elenco = start;
    while(elenco!=NULL)
    {
        printf("%s\n", elenco->titolo);
        printf("%s\n", elenco->autore);
        printf("%d\n", elenco->durata_in_sec);
        printf("%d\n", elenco->rips);
        elenco = elenco->prossima;
    }
    fclose(fp);
    // Free memory
    elenco = start;
    while (elenco != NULL) {
        struct elenco* temp = elenco;
        elenco = elenco->prossima;
        free(temp);
    }
    return 0;
}

这是txt
我们将摇滚你女王2:01这是我的生活邦乔维3:46我们将摇滚你女王2:01表演必须继续女王4:36

daolsyd0

daolsyd01#

1.使用符号常量而不是幻数。
1.首选初始化变量。
1.删除未使用的变量。i仅用于确定是否设置了start,因此也可以将其删除。
1.检查fopen()的返回值。
1.使用str()宏让编译器生成最大字段宽度。
1.“%[^\n]”通常比“%[^\n]%*c”更易读。前者忽略前导白色,而后者只忽略一个尾随字符。

  1. while(!feof())不工作。在这种情况下,您可以通过一个fscanf()调用读取整个记录。这也为您提供了一个检查无效输入/EOF的位置。
    1.检查malloc()的返回值。
    1.当您预分配每条记录时,您需要释放最后一条记录。
    1.确保字符串以“\0”结尾。
  2. fclose()文件,只要你完成。
    1.最小化变量的作用域。这使你的代码更容易推理。
    1.对于迭代,首选for-循环。
    1.考虑将代码分解为更小的函数(elenco_load()elenco_print()elenco_free())。它使推理和测试更容易。
    1.(不固定)考虑使用更具体的类型。是否要允许负durata_in_sec?你希望持续时间为INT_MAX还是更小的类型?secondi < 0 || secondi >= 60是否为有效输入(unsigned char)?
    1.(不固定)当您硬编码rips=1时,请考虑将其从struct elenco中删除,以支持符号常量#define RIPS 1。打印时,您现在只需执行`print(“%d\n”,RIPS)。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define TITOLO_LEN 29
#define AUTORE_LEN 29
#define str(s) str2(s)
#define str2(s) #s

struct elenco {
    char titolo[TITOLO_LEN+1];
    char autore[AUTORE_LEN+1];
    int durata_in_sec;
    int rips;
    struct elenco *prossima;
};

int main() {
    FILE *fp = fopen("musica.txt", "r");
    if(!fp) {
        printf("fopen failed\n");
        return 1;
    }
    struct elenco *start = NULL;
    for(struct elenco *prec = NULL;;) {
        struct elenco *elenco = malloc(sizeof *elenco);
        if(!elenco) {
            printf("malloc failed\n");
            return 1;
        }
        int secondi, minuti;
        int rv = fscanf(fp,
            " %" str(TITOLO_LEN) "[^\n]"
            " %" str(AUTORE_LEN) "[^\n]"
            " %d:%d",
            elenco->titolo,
            elenco->autore,
            &minuti,
            &secondi
        );
        if(rv != 4) {
            free(elenco);
            if(prec)
                prec->prossima = NULL;
            break;
        }
        elenco->durata_in_sec = minuti*60+secondi;
        elenco->rips=1;
        if(!start)
            start = elenco;
        else
            prec->prossima = elenco;
        prec = elenco;
    }
    fclose(fp);

    // Stampa
    for(struct elenco *elenco = start; elenco; elenco = elenco->prossima) {
        printf("%s\n", elenco->titolo);
        printf("%s\n", elenco->autore);
        printf("%d\n", elenco->durata_in_sec);
        printf("%d\n", elenco->rips);
    }

    // Free memory
    for(struct elenco *elenco = start; elenco;) {
        struct elenco* temp = elenco;
        elenco = elenco->prossima;
        free(temp);
    }
    return 0;
}

示例运行:

we will rock you
queen
121
1
it's my life
bon jovi
226
1
we will rock you
queen
121
1
the show must go on
queen
276
1

相关问题