使用getchar()和空格填充进行安全编码
这段代码是更大项目的一部分。我告诉你这是因为它是相关的。我正在开发一个小的(代码)数据库来跟踪我所有的照片。我正在设计它,以便以后可以扩展程序,将引文存储在我所有的论文中 不管是好是坏,我选择了一个带有固定宽度字段的简单平面文件系统。这可能不是对内存的最有效利用,文件的大小也会变小,但它有一些超级优势:没有分隔符,因此文件可以轻松地保持可读性,并具有良好的格式,使用简单的数组索引可以轻松访问数组 我特别喜欢最后一部分,因为它在我的能力范围内。 关于这个数据库的一件事是,我需要能够使很多条目FAAAA…ST!瓶颈出现在用户输入部分,而不是内存,也不是磁盘空间,因此我集中精力使输入变得快速和简单 我了解到用C语言获取用户输入可能是一件棘手的事情。C的字符串处理库有很多函数,可以利用这些函数生成缓冲区溢出。因此,对于这个代码,我在C和C++中实现了Robert C. Seacord的安全编码的一些建议,具体地说是“字符串和缓冲区溢出”。 这里有一个链接: Seacord建议使用fgets()处理输入行,虽然可以安全地处理,但存在性能限制。(我喜欢快,你不喜欢吗?)他进一步建议使用getchar()代替。我就是这么做的 下面是他关于使用while循环安全地使用getchar()的建议:使用getchar()和空格填充进行安全编码,c,getchar,secure-coding,C,Getchar,Secure Coding,这段代码是更大项目的一部分。我告诉你这是因为它是相关的。我正在开发一个小的(代码)数据库来跟踪我所有的照片。我正在设计它,以便以后可以扩展程序,将引文存储在我所有的论文中 不管是好是坏,我选择了一个带有固定宽度字段的简单平面文件系统。这可能不是对内存的最有效利用,文件的大小也会变小,但它有一些超级优势:没有分隔符,因此文件可以轻松地保持可读性,并具有良好的格式,使用简单的数组索引可以轻松访问数组 我特别喜欢最后一部分,因为它在我的能力范围内。 关于这个数据库的一件事是,我需要能够使很多条目FAA
while(( (ch = getchar()) != \n) && ch != EOF)
在我下面的代码中,我稍微调整了一下
我需要I/O做几件事。首先,如果输入的输入太长,我希望它被截断。即使我可能是唯一的用户,我可能会犯错误。其次,如果输入短于字段宽度(主要是这种情况),我想在字段的右侧填充空格
这就是我面临的问题。再多说一点
这个空白保持了平面文件的干净外观,并且再次使索引非常容易。我只需要按“回车”键,然后按顺序进入下一个条目,知道计算机已经按照我想要的方式格式化了数据
(这实际上是E.F.Codd的一个粗略实现,即数据必须被屏蔽,不被直接访问。在数据进入存储之前,所有内容都必须经过检查、抛光、解析等。这可以防止数据损坏。)
在这段代码中,我删掉了所有最后的部分,因为这只是噪音,我非常讨厌试图阅读其他人的代码,他们在他们该死的程序中发布了各种无关的东西,而不仅仅是给他们带来麻烦的部分。同时,我喜欢发布一个可以选择、复制、粘贴、保存和编译的完整程序。所以我在这里做了。我已经在注释和我的小检查中留下了,我将取消注释,以确保一切都是它应该的,然后再次注释掉,所以这不是最简单的代码,但是爱因斯坦那句著名的格言是什么太简单了
无论如何,我知道这一切都有点长,但我想勾勒出我使用的设计原则。你可能会有一个有用的评论。我肯定他会采取愚蠢的方法
我的问题就是如何用正确的空格填充这些字段
我确实想出了一个解决办法。有点
但对我来说,这似乎是一种恶作剧
我只是怀疑有一种更高效、快速或优雅的方式来完成我想做的事情。“hack”部分调用第二个print函数,并使用字符计数和maxlength常量之间的差值在数据后面添加空格。请参见第27-39行。它是有效的…但是
我不应该直接填充阵列吗
我想不出来
代码如下:
#include <stdio.h>
#include <stdlib.h>
/** array-ops/5.c
Template for inputting data from stdin using getchar().
Sets arraymax to prevent overflow, truncates array if smaller than
arraymax, right pads short entries with spaces, and quits gracefully.
(Really? You're /sure/ about that last?) */
#define ARRAYMAX 8
int main(int argc, char *argv[])
{
int ch;
int count;
char array[ARRAYMAX];
ch = getchar();
count = 0;
// no overflows, unclosed processes, or extra keystrokes needed
while(count < ARRAYMAX && ch != '\n' && ch != EOF) {
array[count++] = ch;
ch = getchar();
}
int diff = (ARRAYMAX - count);
//printf("count: %d\n", count); // check
//printf("diff: %d\n", diff); // check again. off-by-one?
int i;
for(i = 0; i < count; i++) {
printf("%c", array[i]);
}
int j;
for(j = 0; j < diff; j++) {
printf("%s", " ");
}
//printf("|\n"); // check, spaces really there?
printf("\n");
return 0;
}
#包括
#包括
/**阵列ops/5.c
使用getchar()从stdin输入数据的模板。
设置arraymax以防止溢出,如果小于,则截断数组
arraymax,右侧用空格填充短条目,然后优雅地退出。
(真的吗?你/确定/关于最后那件事?)*/
#定义ARRAYMAX 8
int main(int argc,char*argv[])
{
int-ch;
整数计数;
字符数组[ARRAYMAX];
ch=getchar();
计数=0;
//不需要溢出、未关闭的进程或额外的击键
而(计数
顺便说一句,我真的在发帖前搜索了这个问题的答案。你可以随意用羽毛击倒我,但似乎每个人都在试图解决一个稍有不同的问题,尤其是对数据保护和缓冲区溢出漠不关心。所以我不认为这是一个重复的问题
[编辑]这是修改后的代码。它结合了Joachim的解决方案和if-else循环来隔离截断的字符串。这仍然不是最好的,但是
#include <stdio.h>
#include <stdlib.h>
/** array-ops/5r.c
Template for inputting data from stdin using getchar().
Sets arraymax to prevent overflow, truncates array if smaller than
arraymax, right pads short entries with spaces, and quits gracefully. */
#define ARRAYMAX 8
int main(int argc, char *argv[])
{
int ch;
int count;
char array[ARRAYMAX];
ch = getchar();
count = 0;
// no overflows, unclosed processes, or extra keystrokes needed
while(count < ARRAYMAX && ch != '\n' && ch != EOF) {
array[count++] = ch;
ch = getchar();
}
int diff = (ARRAYMAX - count);
printf("count: %d\n", count); // check
printf("diff: %d\n", diff); // check again for off-by-one
if(count == ARRAYMAX) {
printf("%.*s", ARRAYMAX, array);
} else {
printf("%.*s%*c", count, array, diff, ' ');
}
printf("|--array ends there\n"); // check, spaces really there?
//printf("\n");
return 0;
}
#包括
#包括
/**阵列ops/5r.c
使用getchar()从stdin输入数据的模板。
设置arraymax以防止溢出,如果小于,则截断数组
arraymax,右侧用空格填充短条目,然后优雅地退出*/
#定义ARRAYMAX 8
int main(int argc,char*argv[])
{
int-ch;
整数计数;
字符数组[ARRAYMAX];
ch=getchar();
计数=0;
//不需要溢出、未关闭的进程或额外的击键
而(计数printf("%.*s%*c\n", count, array, diff, ' ');
#include <stdio.h>
#include <stdlib.h>
#define ARRAYMAX 8
int main()
{
int ch;
int count = 0;
char array[ARRAYMAX] = { 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20 };
int i = 0;
while((ch = getchar()) && count < ARRAYMAX && ch != '\n' && ch != EOF)
array[count++] = ch;
printf("\n 01234567\n");
printf(" array: '");
for (i = 0; i < ARRAYMAX; i++)
printf("%c", array[i]);
printf ("'\n\n");
return 0;
}
$ ./bin/padstr8
Hi
01234567
array: 'Hi '
$ ./bin/padstr8
It's all Good
01234567
array: 'It's all'
char array[ARRAYMAX] = { [0 ... 7] = 0x20 };
char array[ARRAYMAX] = { [0 ... 7] = ' ' };
#include <stdio.h>
#include <stdlib.h>
#define ARRAYMAX 8
/** fill 'str' with input from stdin rt-padded to 'szfld'.
* if 'str' exists and has storage, 'str' is filled with
* input up to a maximum size of 'szfld' chars. If input
* is less than 'szfld', 'str' is rt-padded with spaces.
* if 'str' is 'NULL', 'szfld' chars are allocated.
* NOTE: 'str' is NOT null-terminated. (intentionally)
*/
char *fillfield (char *str, int szfld)
{
char ch = 0;
int count = 0;
int i = 0;
szfld = (szfld > ARRAYMAX) ? ARRAYMAX : szfld;
if (str)
for (i = 0; i < szfld; i++)
str[i] = 0;
else
str = calloc (szfld, sizeof (char));
printf ("\n Input: ");
while((ch = getchar()) && count < ARRAYMAX && ch != '\n' && ch != EOF)
str[count++] = ch;
if (count >= ARRAYMAX && ch != '\n')
while ((ch = getchar()) != '\n' && ch != EOF) ;
char *p = str + szfld - 1;
while (!*p && p >= str) *p-- = 0x20;
return str;
}
int main() {
char field_1[6];
fillfield (field_1, 6); /* fill existing array */
char *field_2 = fillfield (NULL, 6); /* allocate/fill array */
printf ("\n field_1: '%.*s'\n", 6, field_1);
printf (" field_2: '%.*s'\n\n", 6, field_2);
if (field_2) free (field_2); /* clean up allocation */
return 0;
}
$ ./bin/padstrf
Input: hi
Input: hi
field_1: 'hi '
field_2: 'hi '
$ ./bin/padstrf
Input: hi
Input: hi
field_1: ' hi '
field_2: ' hi '
$ ./bin/padstrf
Input: truncate
Input: truncate
field_1: 'trunca'
field_2: 'trunca'
$ ./bin/padstrf
Input:
Input:
field_1: ' '
field_2: ' '