2013-05-12 3 views
0

Я делаю определенный проект для колледжа, который состоит в чтении входного текста и генерации определенного вывода, основанного на нескольких командах. Фокальной точкой для оценки является эффективность, поэтому динамическое распределение памяти - это путь, но я действительно шатко понимаю это.Ошибка сегментации (сбрасывание ядра) в c-указателях и управлении памятью

В любом случае, программа скомпилирована просто отлично, но когда я ее запустил, она быстро обнаружила ошибку сегментации, и я почти уверен, что причиной является плохое управление памятью. После того, как я пытался диагностировать с GDC, я получил это:

(gdb) run proj 
Starting program: /home/dusk/Documents/proj proj 
warning: no loadable sections found in added symbol-file system-supplied DSO at 0x7ffff7ffa000 
5 
hello, I'm me 

Program received signal SIGSEGV, Segmentation fault. 
0x00007ffff7a681c3 in _IO_vfscanf() from /lib/x86_64-linux-gnu/libc.so.6 
(gdb) where 
#0 0x00007ffff7a681c3 in _IO_vfscanf() from /lib/x86_64-linux-gnu/libc.so.6 
#1 0x00007ffff7a70a22 in __isoc99_scanf() 
from /lib/x86_64-linux-gnu/libc.so.6 
#2 0x00000000004009a4 in linelist (n=5) at proj.c:79 
#3 0x000000000040134b in main() at proj.c:226 

Таким образом, очевидно, что проблема (ну ... первая проблема) в функции LineList, которая выглядит следующим образом:

/* Creates a list of strings (each being a line of the input) 
implemented with pointers */ 

char **linelist(int n) 
{ 
char **list; 
list = calloc(n, MAX_STR*sizeof(char)); 
char *input; 
int i; 

for (i = 0; i < n; i++){ 
scanf("%s/n", input); 
list[i] = input; 
} 
return list; 
} 

И это главная функция:

функция
/*MAIN*/ 
int main(){ 
int linesnum = readlinesnum(); 
char **lines = linelist(linesnum); 
char ***matrix = createmat(linesnum, lines); 
char input; 
fstruct ignore; 
ignore.len = 0; 
while (1){ 
    scanf("%c", &input); 
    if (input == 'f'){ 
     ignore = f(ignore); 
    } 
    else if (input == 's'){ 
     s(lines, linesnum); 
    } 
    else if (input == 'l'){ 
     l(matrix, lines, linesnum, ignore); 
    } 
    else if (input == 'w'){ 
     w(matrix, lines, linesnum, ignore); 
    } 
    else if (input == 'h'){ 
     h(matrix, linesnum); 
    } 
    else if (input == -1){ 
     break; 
    } 
} 
freememory(matrix, lines); 
return 0; 
} 

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

спасибо.

+0

В 'linelist' этот' scanf ("% s/n", input); 'записывает в нераспределенную память. –

+1

Какая эффективность - пространство или время? Эффективность времени обычно предполагает использование динамической памяти. –

ответ

1

Эта линия является источником ваших неприятностей:

scanf("%s/n", input); 

Это не только должно быть \n, а не /n (это второстепенный), но вы передаете текущее значение input для scanf когда input неинициализирован. Это не хорошо.Для целых чисел и такие, вы бы по крайней мере взять адрес этого, прежде чем давать его scanf:

scanf("%d", &my_number); 

Однако это не применимо здесь: для %s, он пытается сохранить данные в памяти, вы даете его , Вы даете ему неинициализированный указатель, который может упасть и в любом случае будет никогда делать то, что вы хотите.

Вам нужно выделить память для себя самостоятельно. Например, если вы хотите, чтобы прочитать строку не более 200 символов, вы могли бы сделать что-то вроде этого:

char my_array[201]; /* don't forget to save space for the null byte */ 
scanf("%200s", my_array); 

Тогда вы ограничивая длину линии, хотя, и это не хорошо. Ясно, что нам нужно другое решение.

scanf, вы можете вскоре обнаружить, что это не лучший инструмент для этой работы. Вместо этого мы будем использовать fgets. Алгоритм, который вам нужно реализовать, это:

  1. Следите за тем, насколько мы читали до сих пор. Это будет инициализировано до нуля.
  2. Следите за текущим выделенным размером буфера. Инициализируйте его на что-то разумное.
  3. Выделите память такого размера. (Не забудьте проверить на наличие ошибок.)
  4. Позвоните fgets, передав его &allocated_memory[read_so_far] для буфера и amount_allocated - read_so_far для длины. Вероятно, файл должен быть stdin, чтобы делать то, что вы делали ранее, но это может быть любой читаемый файл. (Опять же, не забудьте проверить наличие ошибок.)
  5. Обновите, насколько мы читали до сих пор.
  6. Проверьте, не читаем ли мы всю строку. Поскольку fgets сохранит новую строку, если есть одна, и новая строка будет существовать, если мы прочитаем всю строку, и мы не находимся в конце файла, мы прочитали всю строку, если перед концом новой строки строки или мы достигли конца файла.
  7. Если мы не прочитали всю строку, удвойте текущий выделенный размер буфера и realloc буфер. Не забудьте проверить наличие ошибок. Затем перейдите к шагу 4.
  8. Если мы дойдем досюда, мы закончим читать строку. Необязательно realloc буфер, чтобы он соответствовал строке точно без пробелов.

Это не так забавно, но это полезно, потому что вы можете обернуть его в функцию. Это какая-то боль, но если вы используете C, возможно, вам стоит привыкнуть к ней.

+0

Спасибо. Это заняло у меня время, чтобы поправиться, но сделал работу ^^ – Dusk252

0

Для начала ваша функция linelist имеет ряд довольно серьезных ошибок.

Во-первых, вы вызываете calloc, но не выделяете достаточно места. Вам нужен массив из char * (указатели длиной 4 или 8 байтов), но вы выделяете массив символов. Короче говоря, замените sizeof(char) на sizeof(char *).

Затем вам нужно выделить место для каждой строки, которые вы читаете в.

Наконец, вы пишете в нераспределенную память в вашем scanf заявлении.

Короче говоря, вам нужно сделать домашнее задание по распределению памяти и т. Д. Я бы также рекомендовал вам отладить ваш код, запустив его с помощью Valgrind.

+0

Хмм ... Моя мысль о том, что у меня было ограничение на размер строк, которые он читал, который определяется как константа 'MAX_STR'. Поэтому умножение этого на 'sizeof (char)' даст максимальный размер строки. И давая, что я хочу массив из них размером 'n', это то, что он должен делать. Я здесь не так? Также. Я попробую Valgrind, и спасибо за полезный ответ. – Dusk252

+0

Все вышесказанное верно, но это будет для одного массива символов, который содержит все строки. Вместо этого вы предположительно хотите иметь массив массивов символов (на основе вашего объявления «char **»).Если вы хотите, чтобы linelist использовался в качестве вектора, вам нужно сначала выделить массив указателей, а затем инициализировать каждый из этих указателей в буфер соответствующего размера. – EmeryBerger

0

В функции linelist эта строка:

scanf("%s/n", input); 

читает в нераспределенную память, которая, кажется, ваша непосредственная проблема, в main если вы делаете правильные вещи. Вы явно не делаете правильные вещи с calloc, но мне непонятно, что вы пытаетесь сделать из образца кода, поэтому не знаете, какое правильное решение есть. Хотя предполагается, что вы пытаетесь создать 2D-массив, этот previous thread должен быть полезен.

+0

Я пытался создать список строк, читая разные строки ввода: каждая строка - одна запись в списке. 'n' - количество строк, ранее прочитанных с ввода. 'MAX_STR' - максимальное количество символов для чтения в строке. – Dusk252

Смежные вопросы