在输出中有两行带有不应该出现的特殊字符。

huangapple go评论71阅读模式
英文:

Two lines in the output with special charachters that shouldn't be there

问题

以下是您提供的文本的翻译:

我有一个以这种格式列出歌曲的txt文件

we will rock you

queen

2:01

我需要将这些数据放入名为"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++;
    }
    
    // 打印
    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);
    // 释放内存
    elenco = start;
    while (elenco != NULL) {
        struct elenco* temp = elenco;
        elenco = elenco->prossima;
        free(temp);
    }
    return 0;
}

这是txt文件的内容:

we will rock you
queen
2:01
it's my life
bon jovi
3:46
we will rock you
queen
2:01
the show must go on
queen
4:36


<details>
<summary>英文:</summary>
I have a txt with a list of songs in this format:
we will rock you
queen
2:01
and i need to put those data in a list named &quot;elenco&quot; with this struct:

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


I tried to store the datas with `fscanf(fp, &quot;%29[^\n]%*c&quot;, elenco-&gt;autore);` (and so on) and the output with a simple `printf(&quot;%s\n&quot;, elenco-&gt;autore);` but the output is correct until the program outputs two lines with special characters like this:
&gt; ?w
&gt;  ☻ ☻ ☻ ☻ ☻ ☻h☻(☻(☻(☻(☻ ☻ ☻ ☻ ☻y
this is the full program if you want to check it

#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(&quot;%s\n&quot;, elenco-&gt;titolo);
printf(&quot;%s\n&quot;, elenco-&gt;autore);
printf(&quot;%d\n&quot;, elenco-&gt;durata_in_sec);
printf(&quot;%d\n&quot;, elenco-&gt;rips);
elenco = elenco-&gt;prossima;
}
fclose(fp);
// Free memory
elenco = start;
while (elenco != NULL) {
struct elenco* temp = elenco;
elenco = elenco-&gt;prossima;
free(temp);
}
return 0;

}


and this is the txt
we will rock you
queen
2:01
it&#39;s my life
bon jovi
3:46
we will rock you
queen
2:01
the show must go on
queen
4:36
</details>
# 答案1
**得分**: 3
1. 使用符号常量代替魔法数字。
2. 更喜欢初始化变量。
3. 删除未使用的变量。 `i` 仅用于确定 `start` 是否已设置,因此可以将其删除。
4. 检查 `fopen()` 的返回值。
5. 使用 `str()` 宏让编译器生成最大字段宽度。
6. `" %[^\n]"` 通常比 `"%[^\n]%*c"` 更可读。前者忽略前导空格,而后者忽略最后一个字符。
7. `while(!feof())` 无法正常工作。在这种情况下,您可以使用单个 `fscanf()` 调用读取整个记录。这还可以让您在一个地方检查无效输入/`EOF`。
8. 检查 `malloc()` 的返回值。
9. 随着每个记录的预分配,您需要释放上一个记录。
10. 确保您的字符串以 '\0' 结尾。
11. 在完成后立即使用 `fclose()` 关闭文件。
12. 限制变量的作用域。这会使您的代码更容易理解。
13. 更喜欢使用 `for` 循环进行迭代。
14. (未修复)考虑将代码拆分为较小的函数(`elenco_load()`、`elenco_print()`、`elenco_free()`)。这会使代码更容易理解和测试。
15. (未修复)考虑使用更具体的数据类型。您是否允许负的 `durata_in_sec`?您是否期望 `INT_MAX` 的持续时间,还是较小的数据类型足够?`secondi < 0 || secondi >= 60` 是否是有效输入(`unsigned char`)?
16. (未修复)由于您硬编码了 `rips=1`,考虑在 `struct elenco` 中将其替换为符号常量 `#define RIPS 1`。这样在打印时您只需执行 `print("%d\n", RIPS)`。
请注意,这些是关于代码的建议和评论,而不是直接的翻译。
<details>
<summary>英文:</summary>
1. Use symbolic constants instead of magic numbers.
1. Prefer initialized variables.
1. Remove unused variables. `i` is only used to determine if `start` has been set so might as well eliminate it, too.
1. Check return value from `fopen()`.
1. Use the `str()` macro to let the compiler generate your maximum field width.
1. &quot; %[^\n]&quot; is usually more readable than &quot;%[^\n]%*c&quot;.  The former ignores leading white space, while the latter ignores exactly one trailing character.
1. `while(!feof())` doesn&#39;t work.  In this case you can read the whole record with a single `fscanf()` call.  This also gives you one place to check for invalid input / `EOF`.
1. Check return value from `malloc()`.
1. As you pre-allocate each record you need to free the last one.
1. Ensure your strings are &#39;\0&#39; terminated.
1. `fclose()` file as soon as you are done.
1. Minimize scope of variables.  This makes your code easier to reason about.
1. Prefer `for`-loops for iteration.
1. (Not fixed) Consider breaking your code into smaller functions (`elenco_load()`, `elenco_print()`, `elenco_free()`).  It makes it easier to reason about and test.
1. (Not fixed) Consider using more specific types.  Do you want to allow negative `durata_in_sec`?  Do you expect duration of `INT_MAX` or would a smaller type do?  Is `secondi &lt; 0 || secondi &gt;= 60` valid input (`unsigned char`)?
1. (Not fixed) As you hard-code `rips=1` consider eliminating it from `struct elenco` in favor of a symbolic constant `#define RIPS 1`.  When printing you now just do `print(&quot;%d\n&quot;, 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-&gt;prossima) {
printf(&quot;%s\n&quot;, elenco-&gt;titolo);
printf(&quot;%s\n&quot;, elenco-&gt;autore);
printf(&quot;%d\n&quot;, elenco-&gt;durata_in_sec);
printf(&quot;%d\n&quot;, elenco-&gt;rips);
}
// Free memory
for(struct elenco *elenco = start; elenco;) {
struct elenco* temp = elenco;
elenco = elenco-&gt;prossima;
free(temp);
}
return 0;

}


and example run:

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


</details>

huangapple
  • 本文由 发表于 2023年6月9日 03:39:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/76435205.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定