在 printf 中的引号(格式)之间添加逗号会改变输出?

Adding comma between quotes (format) in printf changes the output?

提问人:Daniel Boos 提问时间:4/21/2023 最后编辑:Yakov GalkaDaniel Boos 更新时间:4/22/2023 访问量:117

问:

我面临着一个非常奇怪的问题,我只能在 linux 上生成。我真的在互联网上找不到类似的东西,但如果我的搜索技巧不够好,如果这是任何问题的重复,我深表歉意。

采用以下最小可行代码: 在仍然有问题的情况下,我尽可能地削减了开支。

#include <stdio.h>

#define MAX 10
#define MAXNAME 30

typedef struct sup{
    int rating;
    char supName[MAXNAME];
}sup;

typedef struct spec{
    char name[MAXNAME];
    float width;
    float height;
    float depth;
    char material[MAXNAME];
    sup supvisor[MAX];
}spec;

int read_Supervisors(char fileName[], spec *specread){
    int i=0;

    char buffer[MAX];
    FILE *supervisors = fopen(fileName, "r");

    while (i < MAX && fgets (buffer, sizeof(buffer), supervisors)) {

        if(sscanf(buffer, "%19s %d", specread->supvisor[i].supName, &specread->supvisor[i].rating) == 2){
            i++;}}

    fclose(supervisors);

    return i;
}

void read_Specs(char fileName[],spec *spec1){
    FILE *specs = fopen(fileName, "r");

    fscanf(specs, "%29[^\n]\n %19s\n %f\n %f\n %f", spec1->name, spec1->material,&spec1->width, &spec1->height, &spec1->depth);
    fclose(specs);
}

int main(int argc, char *argv[]) {
    spec spec1 = {.name = ""}; // Initialize .name at zero
    //Read specs file.
    read_Specs(argv[1],&spec1);

    int iteration = read_Supervisors(argv[2], &spec1), 
    selectedSuper = 1, 
    calculatedDays = 50;

    float priceOfProject = 1;

    //Print all the values.
    printf("Dear %s,"
           "\nThank you for your order.\n"
           "Your retaining wall of specifications:\n"
           "Material: %s\n"
           "width: %.2f m\n"
           "height: %.2f m\n"
           "depth: %.3f m\n"
           "Will be completed in %d days and the assigned project supervisor is %s\n"
           "The estimated price is: $%.2f\n", spec1.name, spec1.material, spec1.width,spec1.height,spec1.depth,calculatedDays, spec1.supvisor[selectedSuper].supName,priceOfProject);
    return 0;
}

输出:

,ear Jason Oliver
Thank you for your order.
Your retaining wall of specifications:
Material: Concrete
width: 5.50 m
height: 1.00 m
depth: 0.250 m
Will be completed in 50 days and the assigned project supervisor is Sally
The estimated price is: $1.00

请注意,打印出来的是 ,ear 而不是 Dear Jason oliver, 删除逗号时,它可以完美地工作。我可以在逗号之前使用逗号,但不能在逗号之后使用逗号。Dear %s,Dear %s%s

我尝试了很多东西,增加了 #defines,我尝试过拆分为多个 printf,我尝试了不同版本的 C11、C23,我还尝试更新了我的 linux。我要指出的是,这是 linux 的全新安装。

以下是我正在使用的 linux(22.04) 环境的一些信息: Linux Linux 5.19.0-35-generic #36~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC 周五 2 月 17 日 15:17:25 UTC 2 x86_64 x86_64 x86_64 GNU/Linux

编译器版本: gcc (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0

文件结构:

规格 .dat 文件:

Jason Oliver
Concrete
5.50
1.0
0.250

生成器 .dat 文件:

Bob 50
Sally 78
Jian 69
Hecctor 89
C Linux 终端 scanf 行尾

评论

2赞 Retired Ninja 4/21/2023
#define MAX 10太小,无法处理 Builders.dat 中最长的行
0赞 Daniel Boos 4/21/2023
@RetiredNinja,该文件只有 4 个主管,我还有一个检查以确保我在阅读文件时不会超过 10 行。
0赞 Retired Ninja 4/21/2023
char buffer[MAX];那么哪里是超过 10 个字符。fgets (buffer, sizeof(buffer), supervisors)Hecctor 89

答:

8赞 Yakov Galka 4/21/2023 #1

您的输入文件必须使用 Windows 上流行的行尾,而不是 Unix 使用的单行。您的代码将名称读取到字符,因此成为 .当您将名称打印到终端时,指示它将光标移动到行的开头(它是回车控制字符)。在此之后打印的下一个字符是逗号,因此它会覆盖位于同一位置的“Dear”的“D”。\r\n\n\n\rname\r

您也可以修复 your to exclude from the string。请注意,在这种情况下,格式字符串中的以下内容不正确。一个简单的空格就可以跳过 和 ,以及其他空格字符:fscanf\r\n\r\n

fscanf(specs, "%29[^\r\n] %19s %f %f %f", spec1->name, spec1->material,&spec1->width, &spec1->height, &spec1->depth);

或者,如果这是一个选项,您可以使用适用于大多数操作系统的命令修复输入文件:dos2unix

$ dos2unix specs.dat

评论

2赞 Jabberwocky 4/21/2023
好渔获。很遗憾,我们仍然被这种愚蠢的vs所困扰。 问题。'\n''\r\n'
1赞 DevSolar 4/21/2023
@Jabberwocky 实际上是库实现/配置的缺点。该文件已以文本模式(“r”,而不是“rb”)编辑,因此库可以动态转换行尾。当然,更容易不为此烦恼,假设文本模式和二进制模式是相同的,并指向所有不使用单行结束的人......fopen()\n
0赞 Yakov Galka 4/21/2023
@DevSolar AFAIK 转换为不符合 POSIX 标准,因此即使您处于“让我们转换阵营”,这比库实现更像是标准缺点。IMO 虽然 POSIX 做了正确的事情,消除了文本和二进制模式之间的区别。让库进行任何类型的转换都会引入复杂性,可以读取与文件大小报告的数量不同的数量(通过或其他方式),如果程序员没有意识到这一点,这会导致各种错误。\r\n\nfreadcharsftell
3赞 chux - Reinstate Monica 4/21/2023
如果读取单个 or @DanielBoos,则停止该说明符。对于扫描格式的下一部分,它是未读的。%[^\r\n]'\r''\n'
1赞 Ian Abbott 4/22/2023
@DevSolar 实现不需要区分文本流和二进制流。在 POSIX 中,所有流都是二进制流,因此其标准 I/O 库调用无法转换行尾。