Строки длиннее 5 символов не собираются так как надо
Есть программа, которая должна (по условию из упражнения) считывать строки из потока ввода и выводить только те, которые длиннее 5 символов. Ошибок компиляции нет, но работает не так, как мне нужно, а именно либо фильтрация проходит некорректно, либо вывод получается с ошибками. Иногда выводится сплошной мусор
Пример входа:
1. hello
2. 123456
3. foo
4. example
Ожидаемый вывод:
1. 123456
2. example
Текущий вывод:
1. example
Код:
#include <stdio.h>
#define YEAH 1
#define NOT 0
#define MAXLINE 1000
int getline(char* str, int max){
int c, i;
for(i = 0; i < max - 1 && (c = getchar()) != EOF && c != '\n'; ++i)
str[i] = c;
if(c == '\n'){
str[i] = c;
i++;
}
str[i] = '\0';
return i;
}
int copy(char* in, char* from, int start){
for(int i = 0; from[i] != '\0'; i++,start++)
in[start] = from[i];
in[start] = '\0';
return start;
}
int strlen(char* str){
int i = 0;
while(str[i] != '\0')
i++;
return i;
}
int main(void)
{
char str[MAXLINE];
int size;
char str2[MAXLINE*2];
int len;
int start = 0;
while((size = getline(str, MAXLINE)) > 0){
if((len = strlen(str)) > 5){
start = copy(str2,str, start);
}
}
if((len = strlen(str2)) > 5){
printf("\n%s\n","Строки, которые смогли пройти проверку: ");
printf("%s\n",str2);
}
else {
printf("%s\n","Строка/строки не прошли проверку.");
}
return 0;
}
Ответы (2 шт):
- Во-первых, объявите в функции
const char *те строки, которые не должны изменяться. - Во-вторых, у Вас какая-то сложная реализация
getline. - В-третьих, пожалуйста, всегда ставьте фигурные скобки, за исключением единичных операторов выхода/возврата (
break;илиreturn;) в небольших функциях, послеif,while,for, и тд.
В общем-то, вот итоговый вариант:
(size_t - тип, который возвращает оператор sizeof, потому что int не всегда может хранить в себе длину строки (такое маловероятно, но если строка будет прямо умопомрачительно длинной, то значение в int, возможно, выйдет отрицательным (зависит от размера int)))
#include <stddef.h>
#include <stdio.h>
#define MAXLINE 1024
size_t strlen(register const char *s) {
register const char *p = s;
for (; *p; p++) {}
return (size_t) (p - s);
}
size_t getline(char *buf, size_t size) {
size_t was_read = 0;
int ch;
if (0 == size) return 0;
/* for a terminating null byte */
size--;
while (was_read < size) {
ch = fgetc(stdin);
if (EOF == ch) break;
buf[was_read++] = (char) ch;
if ('\n' == ch) break;
}
buf[was_read] = '\0';
return was_read;
}
int main(void) {
char buf[MAXLINE * 4];
char *bufptr;
size_t offset = 0;
size_t was_read;
do {
bufptr = buf + offset;
was_read = getline(bufptr, sizeof(buf) - offset);
if (was_read > 6 /* 5 + 1(\n) */) {
offset += was_read;
}
} while (was_read > 1 /* \n */);
buf[sizeof(buf) - 1] = '\0';
puts(buf);
return 0;
}
alpine ~/Develop/test $ gcc -Wall -Wextra -Werror -pedantic-errors -ansi main.c -o main
alpine ~/Develop/test $ ./main
test
2387216
fd
0
dsjfhasklhf
2387216
dsjfhasklhf
alpine ~/Develop/test $
P.S.: человекам снова что-то не понравилось, однако на этот раз ошибка действительно была моя - я тупо не проверил свой же код) Что ж, перечитав задание, все же, сделал реализацию с выводом в конце и починил все.
P.S.2: сигнатура и работа getline не является таковой (какой она описана в glibc), потому что изначально это была функция fgets, но я думаю, что для Вас такая функция будет даже удобнее.
Это не ответ на вопрос, а демонстрация другого подхода к решению той же задачи.
Поскольку концом строки является символ '\n', то на самом деле для вывода строк длиннее заданной не нужно читать в память всю строку. Достаточно запоминать ее начало, а как только мы прочтем "лишний" символ, то можно вывести запомненные символы, а далее просто печатать все.
Вот такой код решает данную задачу без лишних копирований и т.п.
#include <stdio.h>
#include <stdlib.h>
#define DEF_PREFIX_LEN 5
#define EOL_IS_CRNL 0 // for windows set to 1
/*
Пример входа:
1. hello
2. 123456
3. foo
4. example
Ожидаемый вывод:
1. 123456
2. example
*/
// may has one argument -- prefix lenght
int
main (int ac, char *av[])
{
int pfx_l = av[1] ? atoi(av[1]) : DEF_PREFIX_LEN;
if (pfx_l < 1) {
fprintf(stderr, "invalid line prefix length value: `%s`\n", av[1]);
exit(1);
}
#if EOL_IS_CRNL
pfx_l++;
#endif
// printf("pfx_l = %d\n", pfx_l);
char s[pfx_l + 1];
int c,
l = 0,
out_flag = 0;
while ((c = getchar()) != EOF) {
if (out_flag)
putchar(c);
if (c == '\n') {
l = out_flag = 0;
continue;
}
if (!out_flag) {
s[l++] = c;
if (l > pfx_l) {
for (int i = 0; i < l; i++)
putchar(s[i]);
out_flag = 1;
}
}
}
return puts("\nEnd") == EOF;
}
Компилируем и запускаем:
avp@avp-desktop:~/avp/hashcode$ gcc print_line.c && echo -e "hello\x0a123456\x0afoo\x0aexample" | ./a.out
123456
example
End
avp@avp-desktop:~/avp/hashcode$