LINUX.ORG.RU

K&R Задача 1.16

 ,


0

1

Всем привет. Сразу сорри за нубизм, я только учусь. Пытаюсь решить задачу:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXLINE 2

int _getline(char line[], int maxline);
void copy(char to[], char from[]);

int main() {

    int len;
    int max;
    char c;

    char *buf;
    char *longest;
    max = 0;

    while ((len = _getline(buf, MAXLINE)) > 0) {

        if (buf[len-1] != '\n')
            while ((c = getchar()) != EOF && c != '\n')
                buf[len++] = c;

        buf[len+1] = '\0';

        if (len > max) {
            max = len;
            if ((longest = malloc(sizeof(char) * len)) == NULL)
                printf("error alloc memory");

            copy(longest, buf);
            longest[len] = '\0';
        }
    }
    if (max > 0)
        printf("%d\n%s", max, longest);

    return 0;
}

int _getline(char s[], int lim) {
    int c, i;

    for (i = 0; i < lim-1 && (c = getchar()) != EOF && c != '\n'; ++i)
        s[i] = c;

    if (c == '\n') {
        s[i] = c;
        i++;
    }
    s[i] = '\0';
    return i;
}

void copy(char to[], char from[]) {
    int i;
    i = 0;
    while ((to[i] = from[i]) != '\0')
        i++;
}

Но почему-то ловлю сегфолт при выводе longest. В чем дело?

Deleted

char *buf;

_getline(buf, MAXLINE) (!!!)

int _getline(char s[], int lim) {
    int c, i;

    for (i = 0; i < lim-1 && (c = getchar()) != EOF && c != '\n'; ++i)
        s[i] = c; (!!!)
.....

В общем пишешь неизвестно куда.

ossa ★★ ()

И наверное нужен не просто malloc, а realloc. Код смотрел наискосок.

Cactus64k ()

Изучать C лучше после ассемблера. После этого само отпадёт непонимание того что такое память, указатели и как это всё работает.

ProstoTyoma ()

Буфер не выделен в char *buf;? Вообще указатели занулять надо. Сразу косяки видно будет.

Cactus64k ()

А ничего, что при первом вызове ты пишешь в buf, под который память еще не выделена?

            copy(longest, buf);
            longest[len] = '\0';
Вторая строка не нужна.

Ну и еще по-мелочи косяки.

Eddy_Em ☆☆☆☆☆ ()

Короче, если ты хочешь свой getline написать, то делай так: выделил килобайт, считал данные (при помощи обычного read); если не хватило, то сделал realloc, еще считал. Как только read вернул значение < размера твоего буфера, ты дописываешь trailing zero и возвращаешь этот буфер.

Eddy_Em ☆☆☆☆☆ ()
Ответ на: комментарий от Cactus64k

С килобайтным буфером нифига не будут. Ты часто килобайт с клавиатуры вводишь за один присест?

Проще в полтора-два раза увеличивать буфер при нехватке памяти.

Это стиль быдлокодеров в духе хромоногой быдлоподелки или тормозильского огнелиса.

Eddy_Em ☆☆☆☆☆ ()
Ответ на: комментарий от Eddy_Em

Короче, если ты хочешь свой getline написать, то делай так: [...]

А что в тексте задачи-то?

Какая разница, ты же уже высказался. Давай еще про кои задвинь.

ТС, выдели память.

cdshines ★★★★ ()
Ответ на: комментарий от ossa

функции _getline и copy исправлять не вариант. Исправить нужно только main, по условию задачи.

Deleted ()
Ответ на: комментарий от ProstoTyoma

Изучать C лучше после ассемблера.

взялся за асм, но не могу только учить, без ушибов и глупых вопросов :)

Deleted ()

Перепишите main предыдущей программы так, чтобы она могла печатать самую длинную строку без каких-либо ограничений на ее размер.

Если нельзя пользоваться realloc, то только сохранять в файл.

Eddy_Em ☆☆☆☆☆ ()
Ответ на: комментарий от FIL

В си пришел из луа. А в сях одно время баловался ассемблерными вставками. Доставляло, но потом наскучило и теперь я пишу на сях все подряд=\

Cactus64k ()
Ответ на: комментарий от Cactus64k

Сделал, спасибо большое. И за ссылку спасибо, буду стараться.

Deleted ()
Ответ на: комментарий от Cactus64k

код стал таким: http://sprunge.us/XgVO?c

однако когда набираю hello world код валится с ошибкой:

hello world
*** Error in `./a.out': realloc(): invalid pointer: 0x09249018 ***
======= Backtrace: =========
/lib/libc.so.6(+0x77a1d)[0xb765aa1d]
/lib/libc.so.6(+0x7d2df)[0xb76602df]
/lib/libc.so.6(realloc+0x2bb)[0xb765f32b]
./a.out[0x8048581]
/lib/libc.so.6(__libc_start_main+0xf3)[0xb75fc773]
./a.out[0x80483b1]
======= Memory map: ========
08048000-08049000 r-xp 00000000 08:01 356689     /tmp/a.out
08049000-0804a000 rw-p 00000000 08:01 356689     /tmp/a.out
09249000-0926a000 rw-p 00000000 00:00 0          [heap]
b75e2000-b75e3000 rw-p 00000000 00:00 0 
b75e3000-b7769000 r-xp 00000000 08:01 917302     /lib/libc-2.17.so
b7769000-b776b000 r--p 00186000 08:01 917302     /lib/libc-2.17.so
b776b000-b776c000 rw-p 00188000 08:01 917302     /lib/libc-2.17.so
b776c000-b776f000 rw-p 00000000 00:00 0 
b7773000-b778e000 r-xp 00000000 08:01 912257     /usr/lib/libgcc_s.so.1
b778e000-b778f000 rw-p 0001a000 08:01 912257     /usr/lib/libgcc_s.so.1
b778f000-b7792000 rw-p 00000000 00:00 0 
b7792000-b77b3000 r-xp 00000000 08:01 947381     /lib/ld-2.17.so
b77b3000-b77b4000 r--p 00020000 08:01 947381     /lib/ld-2.17.so
b77b4000-b77b5000 rw-p 00021000 08:01 947381     /lib/ld-2.17.so
bfbcc000-bfbed000 rw-p 00000000 00:00 0          [stack]
ffffe000-fffff000 r-xp 00000000 00:00 0          [vdso]
/bin/bash: line 1: 18545 Аварийный останов         ./a.out

Deleted ()
Ответ на: комментарий от Eddy_Em

С килобайтным буфером нифига не будут. Ты часто килобайт с клавиатуры вводишь за один присест?
Eddy_Em

Ылита не знает что в современных ОС есть IO-redirection и в том числе пайпы? Ну кто бы сомневался :) Жри жёлуди.

anonymous ()

Проблема в том, что в русском переводе ошибка в условии. Никакого выделения памяти к этому моменту ещё не рассматривали. На самом деле в оригинале просят вывести длину самой длинной строки.

grem ★★★★★ ()
Ответ на: комментарий от Deleted

Оптимизацию отключить, дебажную инфу добавить. -O0 -g Будет видно что и где вылетело. Тебе стек вызовов нужен.

У тебя buf не увеличивается. Вот тут из массива вылезает.

if (buf[len-1] != '\n')
   while ((c = getchar()) != EOF && c != '\n')
       buf[len++] = c;

Я так понимаю этот кусок кода пытается читать строку, которую недочитал _getline. Добавь переменную с размером буфера. И будет что то типо этого:

if (buf[len-1] != '\n')
   while ((c = getchar()) != EOF && c != '\n')
   {
       if(buf_len > len)
          buf[len++] = c;
       else
       {
          buf_len = buf_len*2;
          buf = realloc(buf, buf_len);
       }
Дефайн от сюда убери, у тебя буфер будет увеличиваться и нет смысла читать сначала строки всего два символа. Ведь можно прочитать намного больше.
while ((len = _getline(buf, MAXLINE)) > 0) {

Ставь себе eclipse-cdt, gdb и будет тебе счастье. Когда сам погоняешь свой код в дебагере тогда и понимание придет.

Cactus64k ()
Ответ на: комментарий от Deleted

Кстати у тебя в main уже есть половина _getline. Я про тот кусок кода, который дочитывает за _getline строку. Попробуй не использовать _getline и дописать чуток мой говнокод.

Cactus64k ()
Ответ на: комментарий от anonymous

а я бы послушал и посмотрел его код с указателями в реальном режиме. потеха, чо

anonymous ()

int _getline(char line[], int maxline);

Крайне не рекомендую, например. Про крутые идентификаторы, начинающиеся с подчеркиваний лучше сразу забыть, они все зарезервированы.

AptGet ★★★ ()

Вставлю свои пять копеек

$ cat 1.16.c


#include <stdio.h>
#include <string.h>
#include <locale.h>

int main(int argc, char *argv[])
{
        setlocale(LC_ALL, "");
        if (argc < 2) {
                return 1;
        }
        int i = 0;
        size_t len = 0;
        size_t maxlen = 0;
        char *s = NULL;
        for (i = 1; i < argc; i++) {
                len = strlen(argv[i]);
                if (maxlen < len) {
                        maxlen = len;
                        s = argv[i];
                }
        }
        printf("%ld: %s\n", maxlen, s);
        return 0;
}

$ gcc -Wall -Wextra 1.16.c 
$ ./a.out we ivof 33 llllss
6: llllss


У меня в коде масса недоработок, например если два одинаково длинных слова, то покажет только первое и прочих косячков по мелочи.

itn ★★ ()

оо.. работа со строками в Си

есть ли в этом мире что-либо более бессмысленное и беспощадное

unt1tled ★★★★ ()
Ответ на: комментарий от unt1tled

есть ли в этом мире что-либо более бессмысленное и беспощадное

Есть: сайты на пыхпыхе и С++ (а то и жабка или пхытон) для мелкоконтроллеров. Ну и еще всякие си-диезы и прочее ублюдство.

Eddy_Em ☆☆☆☆☆ ()
Ответ на: комментарий от MKuznetsov

Подскажи, как. У меня в голову приходит только вариант записи в файл. Потому что как еще ты сохранишь введенную информацию, которая занимает объем больше, чем буфер, под нее выделенный? Либо realloc, либо write.

Eddy_Em ☆☆☆☆☆ ()
Ответ на: комментарий от Eddy_Em

Ты просто в стандарт никогда не заглядывал.

— All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use.

— All identifiers that begin with an underscore are always reserved for use as identifiers with file scope in both the ordinary and tag name spaces.

AptGet ★★★ ()
Ответ на: комментарий от anonymous

Расскажи нам про указатели в ассемблере.

что нетак с указателями в ассемблере? просто адрес памяти, загружающийся в регистр. потом дереференсишь

unt1tled ★★★★ ()
Ответ на: комментарий от Eddy_Em

Либо realloc, либо write

:-) есть ещё fork(), dup2(), но тут вряд-ли кто с ними справится.

С запретом на использование malloc и memcpy задачка остаётся решаемой, но становится мозгосносящей, экзаменационной на Unix C Programmer.

MKuznetsov ★★★★★ ()
Ответ на: комментарий от AptGet

Где написано что sizeof(char) == 1? Мб это тебе твой любимый компилятор сказал? Не верь ему.

Утечки тут нет. Иди изучай описание функций. После realloc нельзя использовать старый адрес памяти а, не переменную, в которой этот адрес хранился.

Cactus64k ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.