Этот фрагмент кода является частью более крупного проекта. Я говорю вам это, потому что это актуально. Я работаю над небольшой (кодовой) базой данных, чтобы отслеживать все мои фотографии. Я проектирую его так, чтобы впоследствии я мог продлить программу, чтобы сохранить цитаты во всех моих документах.Безопасное кодирование с помощью getchar() и пробелов пробелов
Для лучшего или худшего, я остановился на простой плоской файловой системе с полями фиксированной ширины. Это может быть не самое эффективное использование памяти, а размеры файлов распущены, но у нее есть некоторые преимущества: нет разделителей, поэтому файлы легко остаются удобочитаемыми с хорошим форматированием и легким доступом к массиву с использованием простой индексации массива.
Мне нравится последняя часть, особенно потому, что она лежит в моих навыках. Одна вещь об этой базе данных заключается в том, что мне нужно сделать много записей FAAAA ... ST! Узкое место появляется в пользовательской части ввода, а не в памяти, а не на диске, поэтому я концентрируюсь на том, чтобы сделать ввод злой быстро и просто.
Я узнал, что получение пользовательского ввода на C может быть сложной задачей. В библиотеке обработки строк C имеется множество функций, которые могут быть использованы для генерации переполнения буфера. Итак ... Для этого кода я внедрил некоторые рекомендации от Защищенного кодирования Роберта С. Сиакреда в C и C++ В частности, глава «Переполнение строк и буфера».
Вот ссылка: http://www.informit.com/articles/article.aspx?p=2036582&seqNum=5
Seacord предполагает, что с помощью fgets() для обработки входных линий, а можно делать надежно, имеет ограничения производительности. (Мне нравится быстро, не так ли?) Далее он предлагает использовать getchar(). Вот что я сделал.
Вот его предложение для использования цикла, а для использования GetChar() надежно:
while(((ch = getchar()) != \n) && ch != EOF)
В моем коде ниже, я подправить, что прикосновение.
Есть несколько вещей, которые мне нужны для ввода/вывода. Во-первых, если введенный ввод слишком длинный, я ХОЧУ его усечь. Хотя я, может быть, единственный пользователь, я могу ошибиться. Во-вторых, если вход короче ширины поля, то есть в основном case-я хочу, чтобы это поле было полем справа.
В этом проблема, которую я испытываю. Еще об этом немного.
Это пробелы сохраняют плоский файл в чистоте, и, кроме того, упрощает индексацию. Мне нужно просто нажать клавишу «Ввод» и перейти к следующей записи, последовательно, зная, что компьютер отформатировал данные так, как я этого хочу.
(Это на самом деле принцип неочищенная реализация EF Кодда, что данные должны быть защищено от прямого доступа. Все должно быть проверено, полированная, разобрано и т.д., прежде чем он попадет в хранилище. Это предотвращает повреждение данных.)
В этом коде я вырезал все, что было последним, потому что это просто шум, и мне очень надоело читать код других людей, которые публикуют всю свою проклятую программу со всякими посторонними вещами, а не только роль, которая дает им неприятности. В то же время, я хотел бы опубликовать полную программу, которую можно просто выбрать, скопировать, вставить, сохранить и скомпилировать. Поэтому я сделал это здесь.Я оставил в комментариях и моих маленьких чеках, которые я разорву, чтобы убедиться, что все так, как должно быть, а затем закомментировать, так что это не самый простой код, но что это за знаменитая цитата из Эйнштейна о тоже просто?
Во всяком случае, я знаю все, что немного длиннее, но я хотел набросать принципы дизайна, которые я использовал. У вас может быть полезная критика. Я уверен, что, черт возьми, можно принять глупый подход.
Точная проблема, с которой я столкнулся, заключается в том, как правильно вставлять эти поля с нужным количеством пробелов.
I вычислить решение. Вроде.
Но мне кажется, что это взломан.
Я просто подозреваю, что есть более эффективный, быстрый или элегантный способ выполнить то, что я пытаюсь сделать. Часть «hack» вызывает вторую функцию печати и использует разницу между количеством символов и константой 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;
}
BTW, я действительно искал ответ на это, прежде чем отправлять. Не стесняйтесь сбивать меня пером, но казалось, что каждый пытается решить несколько другую проблему, особенно безразличное безразличие к защите данных и переполнению буфера. Поэтому я не думаю, что это дублированный вопрос.
[редактировать] Вот пересмотренный код. Он включает в себя решение 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;
}
Я не могу понять, почему вы не хотите использовать 'fgets'. – ooga
@ooga Возможно, потому, что OP не хочет, чтобы конечная строка новой строки внутри массива или завершалась как строка. –
Вместо того, чтобы записывать выходные байты и заполнять поле с помощью ввода-вывода файлов, вместо этого вы можете использовать 'memset (array + count, '', diff);' чтобы все оставшиеся байты в массиве были помещены в пробелы. Следуйте этому с помощью 'fwrite (array, sizeof array, 1, FP);', заменяя FP указателем на файл, который может быть 'stdout', как показывает ваш вышеприведенный код. –