Строки длиннее 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 шт):

Автор решения: uint16_t
  • Во-первых, объявите в функции 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, но я думаю, что для Вас такая функция будет даже удобнее.

→ Ссылка
Автор решения: avp

Это не ответ на вопрос, а демонстрация другого подхода к решению той же задачи.

Поскольку концом строки является символ '\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$ 
→ Ссылка