long long int不好做long int

时间:2020-02-24 15:53:53

标签: c++ printf

当我的一个朋友问我如何用主机游戏项目调试问题时,我发现fprintf在C语言中发生了奇怪的转换,我无法弄清。该项目需要跟踪所有信息,包括分数和使用C更新到.txt文件的时间。

-初始化

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
.
.
.
// in main
    time_t timer;
    time (&timer);
    int num=0,c;
    scanf(" %s %ld", inputname,c);
    fscanf(fp, "%d", &num);
    num++;
    char **name;
    long *times;
    ull *score;

    name = new char *[num];
    for(int i=0; i<num; i++){
        name[i] = new char[MAX];
    }
    times = new long [num];
    score = new ull[num];

    //new data
    name[num-1] = inputname;
    score[num-1] = c;
    times[num-1] = timer;

-I / O部分

.
.
.
// input from file after dynamic variables have fix size
    for(int i=0; i<num-1; i++){
        fscanf(fp, " %s%d", name[i], &score[i]);
        fscanf(fp, "%ld", &times[i]);
    }

    fseek(fp , 0 , SEEK_SET);
    fprintf(fp, "%d\n", num);

//print back to fp
    for(int i=0; i<num; i++){

        fprintf(fp, "%s %ld ",name[i], score[i]);
        fprintf(fp, "%ld\n",times[i]);  
    }

问题。如果我更改

    fprintf(fp, "%s %ld ",name[i], score[i]);
    fprintf(fp, "%ld\n",times[i]);  

到一行

fprintf(fp, "%s %ld %ld\n",name[i], score[i],times[i]);

输出文件将具有

NAME1 SCORE1 TIMEINLONG1
NAME2 SCORE2 0
NAME3 SCORE3 0
.
.
.

代替

NAME1 SCORE1 TIMEINLONG1
NAME2 SCORE2 TIMEINLONG2
.
.
.

经过一番尝试,我发现通过颠倒分数和时间的顺序

fprintf(fp, "%s %ld %ld\n",name[i], times[i],score[i]);

我的输出正确

NAME1 TIMEINLONG1 SCORE1
.
.
.
再次

因此,C如何处理输出流。我以为编译器会收集"..."中的参数以组装一个字符串,然后将其刷新到ou​​tputstream。显然,它忽略了第一个(time [0])之后的time [i]。

这是我初始化时间的方式的问题吗? 还是fprintf()有问题?

对这么长的页面表示歉意,但现在我对fprint感到困惑。


已解决

将标题从“具有动态内存的fprintf”编辑为“ long long int不好用long int,反之亦然。”

问题不是动态内存问题(抱歉,我不知道),而是我用来获取数据并将其放入printf,fprintf,scanf,fscanf中的类型。根据@Adrian Mole的说法,不匹配将long int分配给long long int类型的变量是未定义行为,并且以下I / O操作将无法正确执行。似乎即使long long int的空间也比long long的空间大,这是不兼容的。

long long int c;
scanf("%d",&c);
printf("%d",c);
//or
scanf("%ld",&c);
printf("%ld",c);

long long int c;
scanf("%lld",&c);
printf("%lld",c);

3 个答案:

答案 0 :(得分:3)

您在这里有一个经典的例子,“行为未定义!”假设score[i]的变量是{假设类型ull的合理定义)是 unsigned long long int (可能/可能是64位),但两者都是{{1 }}和“冒犯” scanf调用使用printf格式说明符(可能/可能是指32位变量)。

以格式说明符和给定参数之间的“不匹配”调用%ld时,您处在未定义行为领域!

通过为相应的printf参数指定%llu格式来解决此问题!例如,代替:

score[i]

使用:

fprintf(fp, "%s %ld %ld\n",name[i], score[i],times[i]);

随时要求进一步的澄清和/或解释。

答案 1 :(得分:1)

问题从以下几行开始:

int num=0,c;
scanf(" %s %ld", inputname, c);

首先,您应该写&c而不是c作为最后一个参数。由于scanf会写入其参数,因此它应该接收参数的地址(字符串除外,我很懒于解释原因)。

第二,由于cint,因此您需要%d,而不是%ld。小心尺寸。

关于您的fprintf-再次注意大小。由于scoreull*,并且我假设ull的意思是unsigned long long,因此您需要以%llu格式而不是%ld进行打印。 (请注意-Andrian Mole也指出了这篇文章,并在我发布我的答案之前先发布了他的答案。)

答案 2 :(得分:0)

另一个错误是:

name[num-1] = inputname;

这会将指针重新分配给堆分配的内存,并导致内存泄漏。 inputname数组应复制到name[n]数组中,例如

snprintf(name[num-1], MAX, "%s", inputname);

scanf %s可能会溢出其目标数组参数,除非您对目标大小进行硬编码,例如:

#define MAX 256
int num=0,c;
char inputname[MAX];
scanf("%256s %d", inputname, c);
相关问题