Необъяснимое переполнение в C - PullRequest
0 голосов
/ 03 февраля 2020

Я пишу код, чтобы найти самую длинную строку во входном потоке и распечатать ее. Однако после того, как я определил int с именем max_count = 0, я всегда находил переполнение, которое отображало max_count как 1633771873. Я инициализировал эту переменную, поэтому я не знаю, в чем проблема. Возможно, вам не нужно разбираться со всеми функциями, но каждая из них имеет свой комментарий.

Вот мой код:

#include <stdio.h>
#define DEFAULT 10

int getline(char line[], int limit);
void copy(char from[], char to[]);
int enlarge(int lim, char s[]);

main() 
{
    int i;
    int max_count = 0;
    char line[DEFAULT];
    char maxline[DEFAULT];
    while ((i = getline(line, DEFAULT)) != 0) {
        if (i > max_count) {    // where weird thing happend (max_count=1633771873)
            max_count = i;
            copy(line, maxline);
        }
    }
    if (max_count > 0) {
        printf("maxline: %s", maxline);
    } else {
        printf("No maxline");
    }
    return 0;
}

/*get a row from input stream and return its length*/
int getline(char s[], int lim)
{
     int i, c;
     for (i = 0; ((c = getchar()) != EOF) && (c != '\n'); ++i) {        
        if (i == lim - 1) {
            lim = enlarge(lim, s); 
        }
        s[i] = c;
     }
     if (c == '\n') {
        s[i] = c;
        ++i;
     }
     if (i == lim) {
        enlarge(lim, s); 
     }
     s[i] = '\0';
     return i;
}

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

/*expand an array twice as its capacity*/
int enlarge(int lim, char s[]) 
{   
    s[lim - 1] = '\0';
    lim *= 2;
    char temp[lim];
    copy(s, temp);
    s = temp;   
    return lim;
}

Это окно консоли:

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
^Z
maxline: 
--------------------------------
Process exited after 15.19 seconds with return value 3221225477

Ответы [ 2 ]

2 голосов
/ 03 февраля 2020

Ваша enlarge функция не делает то, что вы думаете.

int enlarge(int lim, char s[]) 
{   
    s[lim - 1] = '\0';
    lim *= 2;
    char temp[lim];
    copy(s, temp);
    s = temp;   
    return lim;
}

Вы создаете новый массив temp в рамках функции. Затем вы копируете адрес начала массива в s. Поскольку s является параметром функции, изменение s не будет отражено в вызывающей функции. Поэтому после возврата этой функции s в getline остается неизменным.

Даже если вы должны были это исправить, либо вернув char *, либо изменив функцию на принятие char ** и присвоив temp в разыменованный указатель вы бы возвращали адрес локальной переменной enlarge. Эта переменная выходит из области видимости, когда функция возвращается, поэтому указатель будет недействительным.

Единственный способ изменить размер массива - это сначала динамически выделить его с помощью malloc, а затем использовать позже. realloc для изменения его размера.

Кроме того, getline - это имя функции в системах POSIX. Вы должны изменить имя на другое.

2 голосов
/ 03 февраля 2020

У вас есть буфер с пробелом для 10 символов:

#define DEFAULT 10
char line[DEFAULT];

Вы вводите 37 символов, включая символ новой строки:

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

Ваша функция getline пытается сохранить их все в line (кстати, enlarge не делает ничего полезного).

Первые 10 символов вписываются в line. Другие 27 символов и завершающий '\0' перезаписывают другие случайные переменные, которые идут после line в памяти.

Именно поэтому max_count содержит коды ASCII для aaaa.

...