我正在尝试使用 stdout 文件指针通过 fputc 输出我的数据。代码看起来像这样:
...
int c;
FILE *in, *out;
...
in = fopen(*argv++, "r");
if (!in) {
printf("failed to open file %s\n", *(argv - 1));
return 1;
}
out = (o) ? fopen(*argv++, "w") : stdout; [1]
if (!out) {
printf("failed to open file %s\n", *(argv - 1));
return 1;
}
...
while ((c = fgetc(in)) != EOF) { [2]
...
}
...
我不提供输出文件,因此,我的
out
文件指针指向 stdout
。
当我尝试使用 fputc
在 stdout
中输出数据时,如
fputc(c, out); /* not inside the loop above, and 'c' has completely different value */
我遇到分段错误。赋值 (
out
) 和使用 (out = stdout
) 之间没有提及 fputc(c, out)
。
尽管如此,我发现由于某种神奇的原因,在使用时(fputc
),out
指向而不是stdout
,
但位于 <stdout + 6>
(stdout
地址后 6 个字节)。我不知道为什么。这是我的调试器会话。
断点1:
(gdb) c
Continuing.
Breakpoint 3, main (argc=1, argv=0x7fffffffe200) at source.c:73
73 out = (o) ? fopen(*argv++, "w") : stdout;
(gdb) n
Hardware watchpoint 2: out
Old value = (FILE *) 0x0
New value = (FILE *) 0x7ffff7fa7780 <_IO_2_1_stdout_>
main (argc=1, argv=0x7fffffffe200) at source.c:74
断点2:
(gdb) c
Continuing.
Hardware watchpoint 2: out
Old value = (FILE *) 0x7ffff7fa7780 <_IO_2_1_stdout_>
New value = (FILE *) 0x7ffff7fa7781 <_IO_2_1_stdout_+1>
main (argc=1, argv=0x7fffffffe200) at source.c:80
80 while ((c = fgetc(in)) != EOF) {
发生了很多事情(至少对我来说)。但这里的关键点是
out
文件指针的值在没有任何明显原因的情况下增加。我需要一些帮助
语言律师(或懂得 C 的人)。这个神奇的功能是叫“UB”还是别的什么?
在这个循环中,我将 in
文件指针与 stdin
进行比较,使用我的动态字符串(听起来像麻烦)和一个整数数组。
无论如何,这与流无关(或者至少我希望如此)。
我期望文件指针指向同一位置而不改变其自身的值。这个问题可能没有提供太多信息,但我认为其他细节与文件指针或 i/o 流无关。
更新: 正如许多人在评论中指出的那样,没有足够的信息。抱歉。这是完整的代码。
#include <stdio.h>
#include <stdlib.h>
#define MAX 'e'
typedef struct {
char *s;
char *t;
char *u;
int l;
} string;
void put_char(string *s, char c)
{
if (!s->s) {
s->s = malloc(s->l = 2);
s->t = s->s;
s->u = s->s;
} else if (s->t - s->s >= s->l) {
if ((s->s = realloc(s->s, s->l <<= 1)) == NULL) {
printf("failed to reallocate string\n");
return;
}
s->t = s->s + (s->l >> 1);
s->u = s->s;
}
*s->t++ = c;
}
int get_char(string *s)
{
if (*s->u)
return *s->u++;
else
return 0;
}
int caesar(int c, int s)
{
if (isalpha(c))
return ((tolower(c) - 'a' + s) % 26 + 26) % 26 + 'a';
else
return c;
}
int main(int argc, char const *argv[])
{
int d[26];
int c, f, i, m, o;
FILE *in, *out;
string s;
i = o = 0;
while (--argc > 0 && **++argv == '-')
while (c = *++*argv)
switch (c) {
case 'i':
i = 1;
break;
case 'o':
o = 1;
break;
default:
printf("decrypt: illegal option %c\n", c);
break;
}
in = (i) ? fopen(*argv++, "r") : stdin;
if (!in) {
printf("failed to open file %s\n", *argv);
return 1;
}
out = (o) ? fopen(*argv++, "w") : stdout;
if (!out) {
printf("failed to open file %s\n", *argv);
return 1;
}
for (i = 0; i < 26; i++)
*(d + i) = 0;
while ((c = fgetc(in)) > 0) {
if (in == stdin)
put_char(&s, c);
if (isalpha(c))
(*(d + c - 'a'))++;
}
if (in == stdin)
put_char(&s, '\0');
for (i = m = 0; i < 26; i++)
if (*(d + i) > *(d + m))
m = i;
f = -abs('a' + m - MAX);
if (in == stdin) {
while ((c = get_char(&s)) > 0)
fputc(caesar(c, f), out);
} else {
fseek(in, 0, SEEK_SET);
while ((c = fgetc(in)) > 0)
fputc(caesar(c, f), out);
}
return 0;
}
您的所有
get_char(&s)
和 put_char(&s)
调用都会表现出 未定义的行为,因为您在进行这些调用之前尚未初始化 s
的任何成员。在评估 s->s
之前,if (!s->s)
没有任何有意义的值(并且可能与 s->u
中的 if (*s->u)
相同),因此之后的一切都是可疑的。您需要初始化 string
成员。