我的问题是,当我尝试使用“\ n”打印文本时,这个特殊字符对于printf是不可见的,并在将其回显到文件并再次读取后放置。
#include <stdio.h>
#include <string.h>
int main()
{
FILE *f;
char *s = (char*) malloc (2919);
strcpy(s, "printf 'H4sIAIM4aFYCAwtJLS6JyQsBklwAMrDLnwsAAAA=' | base64 -d | gunzip > r"); //Test\nTest after decoding
system(s);
f = fopen("r", "r");
fseek(f, SEEK_SET, 0);
fread(s, 2919, 1, f);
printf("%s", s); //puts(s); gives the same result
fclose(f);
system("rm r");
free(s);
return 0;
}
输出应如下所示:
Test
Test
它看起来像Test\nTest
。我究竟做错了什么?
学习目的,所以请你好。
答案 0 :(得分:4)
您编码的文字如下所示:
Test\nTest
这是一个带有&#34; \&#34;的10个字符的字符串。对于第五个角色和&#34; n&#34;为第六个。这不同于:
char str[]="Test\nTest";
这是一个9个字符的字符串,第五个字符带有换行符。
如果要打印换行符,则编码的字符串需要包含它。或者,或者你必须解析结果字符串并手动执行换行符替换。
答案 1 :(得分:3)
您的代码存在以下问题:
fseek(f, SEEK_SET, 0);
没有任何意义,默认情况下,使用fopen
打开的文件位于第0位。
fread(s, 2919, 1, f);
:您不存储读取的字节数。您不能正确地为printf终止缓冲区以在最后一个解码字节处停止。你怎么知道文件大小?
编码后的字符串H4sIAIM4aFYCAwtJLS6JyQsBklwAMrDLnwsAAAA=
解码为Test\nTest
,后跟\
字符,后跟n
,而不是换行符。使用r
从文件fread
中读取这些字符不会将转义序列\n
转换为实际的换行符。在解析字符串和字符文字时,这种转换是编译器的一个特性。如果您打算对文件内容执行此操作,则必须亲自手动编写转换代码。
以下是更正后的版本:
#include <stdio.h>
#include <string.h>
int main(void) {
FILE *f;
char *s = malloc(2919 + 1);
char *p;
int nread;
strcpy(s, "printf 'H4sIAIM4aFYCAwtJLS6JyQsBklwAMrDLnwsAAAA=' | base64 -d | gunzip > r"); //Test\nTest after decoding
system(s);
f = fopen("r", "r");
nread = fread(s, 2919, 1, f);
if (nread >= 0) {
s[nread] = '\0';
while ((p = strstr(s, "\\n")) != NULL) {
/* converting \ n sequences to linefeed characters */
*p = '\n';
memmove(p + 1, p + 2, strlen(p + 2) + 1);
}
printf("%s", s); //puts(s); will not give the same result
}
fclose(f);
system("rm r");
free(s);
return 0;
}
答案 2 :(得分:2)
很明显,您已经在字符串中的相应位置编码了字节'\'
和'n'
。
如果你不想要,你可以
压缩并编码正确的字符串:
$ echo $'Test\nTest' | gzip | base64
H4sIAEs+aFYAAwtJLS7hCgERAF0muOIKAAAA
$ echo $'Test\nTest' | gzip -n | base64
H4sIAAAAAAAAAwtJLS7hCgERAF0muOIKAAAA
或以某种方式解释字符串中的\n
。但这会使一切变得更加复杂。
答案 3 :(得分:2)
@lurker已经敲了敲头......
编码显然有一个字面反斜杠,而你的内容中没有任何内容 系统命令管道解释它。一种方法来实现它 解释转义是:&#34; echo -e $(printf &#39; H4sIAIM4aFYCAwtJLS6JyQsBklwAMrDLnwsAAAA =&#39; | base64 -d | gunzip解) R&#34;
在回答这个问题时要更加冗长 - 特别是发生了什么事情,你已经压缩了文字ASCII(或UTF-8)字符:
T e s t \ n T e s t
鉴于你的问题,你(大概)意味着压缩一个新的行字符(通常由字符串\n
中的工具解释)而不是两个文字字符\
和{{1 }}
您可以创建不同的gzip压缩输入。这是一个选择。我不知道你是如何生成当前gzip压缩二进制数据的 - 如果你发布了这个数据,我们可以看看并提出修复建议。
或者正如@lurker所说 - 您可以在输出上执行某些操作,将n
和\
的任何出现转换为换行符 - 并且有很多如何做到这一点。
但这实际上取决于你想要做什么。如果你认为你已经压缩了这段文字:
n
...然后是输入错误。
如果您认为自己已压缩此文字:
Test
Test
...(如字面意思为反斜杠和n),那么你可能正在尝试添加一些输出处理以将其转换为真正的新行字符。
这有意义吗?
答案 4 :(得分:2)
C编译器转换&#34; \ n&#34;只有在文字字符串(源代码中显示的常量)中遇到,而不是在任何字符串变量中,才会将序列转换为换行符(ASCII码10)。
示例:
char s1[] = "TEST\nTEST";
printf(s1); // ---> TEST newline TEST.
char s2[] = "TEST\\nTEST"; // s2 = "TEST\nTEST"
printf(s2); // ---> TEST\nTEST (the characters \ and n are present inside the string)
如您所见,在s1
的情况下,字符串首先由C编译器解析,然后将\n
转换为换行符。在第二种情况下,转义字符\
阻止了解释,因此字符串s2
正好是TEST\nTEST
,但现在这不再是文字(在代码中明确给出),而是驻留在内存中的真实字符串。因此它将不再被解释。
因此,printf(s2)
与printf("TEST\nTEST")
不同,因为在前一种情况下没有解释,而在后一种情况下,C编译器会看到一个文字,并会解释它,取代{{1} } \n
。