当我的一个朋友问我如何用主机游戏项目调试问题时,我发现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", ×[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如何处理输出流。我以为编译器会收集"..."
中的参数以组装一个字符串,然后将其刷新到outputstream。显然,它忽略了第一个(time [0])之后的time [i]。
这是我初始化时间的方式的问题吗? 还是fprintf()有问题?
对这么长的页面表示歉意,但现在我对fprint
感到困惑。
问题不是动态内存问题(抱歉,我不知道),而是我用来获取数据并将其放入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);
答案 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会写入其参数,因此它应该接收参数的地址(字符串除外,我很懒于解释原因)。
第二,由于c
是int
,因此您需要%d
,而不是%ld
。小心尺寸。
关于您的fprintf-再次注意大小。由于score
是ull*
,并且我假设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);