使用sprintf()/write()的C程序有额外的字符
我正在编写一个C程序,其中用户将10个整数输入到一个数组中,该程序在控制台上输出该数组的倒数,并将其写入一个文件。我的程序唯一的问题是,在两个输出中都有额外的字符。在控制台中,第一个整数前面有一个“%”。在我写入的文件中,每个整数前面都有两个空框,第一个除外(最后一个整数后面还有一行)使用sprintf()/write()的C程序有额外的字符,c,printf,fwrite,C,Printf,Fwrite,我正在编写一个C程序,其中用户将10个整数输入到一个数组中,该程序在控制台上输出该数组的倒数,并将其写入一个文件。我的程序唯一的问题是,在两个输出中都有额外的字符。在控制台中,第一个整数前面有一个“%”。在我写入的文件中,每个整数前面都有两个空框,第一个除外(最后一个整数后面还有一行) #include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #inc
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char const *argv[]) {
int i;
int input;
char *filename = "/home/privateinfo/5/output";
char *buffer = malloc(sizeof(int));
int *tenInts = malloc(10 * sizeof(int));
/* open the file for writing */
int fd = open(filename, O_WRONLY | O_TRUNC);
if (fd < 0) {
return -1;
}
/* read ten integers from keyboard and store in array*/
write(1, "Enter 10 integers:\n", 20) ;
for (i = 0; i < 10; i++) {
scanf("%d", &input);
tenInts[i] = input;
}
write(1, "\nThe integers reversed are:\n", 30);
/* print array in reverse and write to file*/
for (i = 9; i > -1; i--) {
sprintf(buffer, "%d\n", tenInts[i]);
write(1, buffer, sizeof(int));
if(write(fd, buffer, sizeof(int)+1) < 0) {
write(2, "There was an error writing to the file.\n", 50);
return -1;
}
}
/* close the file and clear pointer */
close(fd);
return 0;
}
#包括
#包括
#包括
#包括
#包括
int main(int argc,char const*argv[]{
int i;
int输入;
char*filename=“/home/privateinfo/5/output”;
char*buffer=malloc(sizeof(int));
int*tenInts=malloc(10*sizeof(int));
/*打开文件进行写入*/
int fd=打开(文件名,O_WRONLY | O_TRUNC);
如果(fd<0){
返回-1;
}
/*从键盘读取十个整数并存储在数组中*/
写入(1,“输入10个整数:\n”,20);
对于(i=0;i<10;i++){
scanf(“%d”,输入(&I));
tenInts[i]=输入;
}
写入(1,“\n反转的整数为:\n”,30);
/*反向打印数组并写入文件*/
对于(i=9;i>-1;i--){
sprintf(缓冲区,“%d\n”,tenInts[i]);
写入(1,缓冲区,sizeof(int));
if(写入(fd,缓冲区,sizeof(int)+1)<0){
写入(2,“写入文件时出错。\n”,50);
返回-1;
}
}
/*关闭文件并清除指针*/
关闭(fd);
返回0;
}
底线是,您没有为
缓冲区
分配足够的存储空间,并且当您试图在缓冲区
中存储的字符超过您的空间时,很可能会调用未定义的行为。此外,当您试图向标准输出
写入更多字符时,也会调用未定义的行为您在字符串文字的字符计数中有一个(或多个)字符,因为“\n”
是一个字符(换行符、ASCII10
或0xa
),而不是'\'
和'n'
的多个字符
不幸的是,这只是冰山一角。首先,请注意,避免在代码中硬编码幻数(10
是一个幻数),并避免硬编码文件名)。如果因为需要11
整数而需要更改像10
这样的数字,请查看需要进行多少更改。如果要写入其他文件,则必须重新编译代码。请改为:
#define NINT 10 /* if you need a constant, #define one (or more) */
#define INTCHARS 32 /* adequate for LLONG_MIN or ULLONG_MAX (20+1 chars) */
#define FCRMODE S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH
现在,如果需要进行更改,您可以在代码顶部的单个位置更改常量
对于文件名,您可以提供一个默认值,但当声明为时,您的程序接受main
的参数:
int main (int argc, char **argv) {
将文件名作为参数传递给您的程序,或使用硬编码文件名作为默认值。示例:
char *filename = argc > 1 ? argv[1] : "/home/privateinfo/5/output";
如果提供了参数,则将其用作文件名,否则将使用默认值
在您的分配中:
char *buffer = malloc(sizeof(int));
您只能将4个字节分配给缓冲区
,这意味着您最多只能存储3位数字和nul终止字符,或者由于您还包括'\n'
字符,您最多只能存储2位数字。相反,没有理由分配缓冲区。最长的长整型
或无符号64位计算机上的long-long
是20个字符(包括'-'
减号)+1
作为nul终止字符,总共需要21个字符。只需定义一个32字节的缓冲区,您就可以将'\n'
包含10个安全字符,例如
char buffer[INTCHARS] = "";
接下来,不要为write
计算字符数。如果您打印字符串文字,只需使用strlen()
即可获得适当数量的字符以进行输出。或者,如果您需要创建一个字符串以使用sprintf
进行写入,保存返回值它会告诉您写入缓冲区的字符数(不包括nul终止字符),例如
(当您可以将字符串直接转换为stdout
时,为什么要使用write
是一个谜。)
不要将负值返回到shell。POSIX要求只返回正值。这就是宏EXIT\u FAILURE
被定义为1
的原因
其余错误只是上述内容的附加合并。总而言之,您可以:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define NINT 10 /* if you need a constant, #define one (or more) */
#define INTCHARS 32 /* adequate for LLONG_MIN or ULLONG_MAX (20+1 chars) */
#define FCRMODE S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH
int main (int argc, char **argv) {
int fd, i, input, nchar, *tenInts;
char *filename = argc > 1 ? argv[1] : "/home/privateinfo/5/output";
char buffer[INTCHARS] = "";
if (!(tenInts = malloc (NINT * sizeof *tenInts))) {
perror ("malloc-tenInts");
return 1;
}
/* open the file for writing */
if ((fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, FCRMODE)) < 0) {
perror ("fopen-filename");
return 1;
}
/* read NINT integers from keyboard and store in array*/
nchar = sprintf (buffer, "Enter %d integers:\n", NINT);
write (STDOUT_FILENO, buffer, nchar); /* (or simply use printf) */
for (i = 0; i < NINT; i++) {
if (scanf ("%d", &input) != 1) {
fputs ("error: invalid integer input.\n", stderr);
return 1;
}
tenInts[i] = input;
}
write (STDOUT_FILENO, "\nThe integers reversed are:\n",
strlen ("\nThe integers reversed are:\n"));
/* print array in reverse and write to file*/
for (i = NINT-1; i >= 0; i--) {
nchar = sprintf (buffer, "%d\n", tenInts[i]);
write (STDOUT_FILENO, buffer, nchar);
if (write (fd, buffer, nchar) < 0) {
write (STDERR_FILENO, "There was an error writing to the file.\n",
strlen ("There was an error writing to the file.\n"));
return 1;
}
}
/* ALWAYS validate close of file (after a write) */
if (close (fd) == -1)
perror ("close-fd");
return 0;
}
输出文件
$ cat dat/tenintwrite.txt
100
90
80
70
60
50
40
30
20
10
仔细检查一下,如果您有进一步的问题,请告诉我。缓冲区的长度与大小(int)
之间没有相关性。您不能将一个int
写入标准输出
(例如,使用写入(1,缓冲区,大小(int));
--需要多少字节“4312981”
),您可以fputs(buffer,stdout);
(您可以简单地put(buffer)
,但是您在buffer
中包含了'\n'
(出于某种奇怪的原因)。不要将-1;
返回到shell。返回1;
以指示错误。您无法正确使用任何输入函数(如scanf(“%d”,&input);
)除非您检查返回。“输入10个整数:\n”
仅为19
个字符,而不是20
,“\n”
是单个字符(ASCII 10,0xa)。我将写调用改为使用strlen(缓冲区),而不是以前的操作。我还删除了“\n”从缓冲区。这两个修复为我解决了它,谢谢。我是一个有点新的,所以idk如果有一种方法来标记一个评论作为一个正确的答案。
$ ./bin/tenintwrite dat/tenintwrite.txt
Enter 10 integers:
10 20 30 40 50 60 70 80 90 100
The integers reversed are:
100
90
80
70
60
50
40
30
20
10
$ cat dat/tenintwrite.txt
100
90
80
70
60
50
40
30
20
10