使用getchar()和空格填充进行安全编码

使用getchar()和空格填充进行安全编码,c,getchar,secure-coding,C,Getchar,Secure Coding,这段代码是更大项目的一部分。我告诉你这是因为它是相关的。我正在开发一个小的(代码)数据库来跟踪我所有的照片。我正在设计它,以便以后可以扩展程序,将引文存储在我所有的论文中 不管是好是坏,我选择了一个带有固定宽度字段的简单平面文件系统。这可能不是对内存的最有效利用,文件的大小也会变小,但它有一些超级优势:没有分隔符,因此文件可以轻松地保持可读性,并具有良好的格式,使用简单的数组索引可以轻松访问数组 我特别喜欢最后一部分,因为它在我的能力范围内。 关于这个数据库的一件事是,我需要能够使很多条目FAA

这段代码是更大项目的一部分。我告诉你这是因为它是相关的。我正在开发一个小的(代码)数据库来跟踪我所有的照片。我正在设计它,以便以后可以扩展程序,将引文存储在我所有的论文中

不管是好是坏,我选择了一个带有固定宽度字段的简单平面文件系统。这可能不是对内存的最有效利用,文件的大小也会变小,但它有一些超级优势:没有分隔符,因此文件可以轻松地保持可读性,并具有良好的格式,使用简单的数组索引可以轻松访问数组

我特别喜欢最后一部分,因为它在我的能力范围内。 关于这个数据库的一件事是,我需要能够使很多条目FAAAA…ST!瓶颈出现在用户输入部分,而不是内存,也不是磁盘空间,因此我集中精力使输入变得快速和简单

我了解到用C语言获取用户输入可能是一件棘手的事情。C的字符串处理库有很多函数,可以利用这些函数生成缓冲区溢出。因此,对于这个代码,我在C和C++中实现了Robert C. Seacord的安全编码的一些建议,具体地说是“字符串和缓冲区溢出”。 这里有一个链接:

Seacord建议使用fgets()处理输入行,虽然可以安全地处理,但存在性能限制。(我喜欢快,你不喜欢吗?)他进一步建议使用getchar()代替。我就是这么做的

下面是他关于使用while循环安全地使用getchar()的建议:

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: '      '