2013-08-10 2 views
0

Только что выучил С на этой неделе. Моя задача состоит в том, чтобы получить большой большой целочисленный ввод от пользователя, сохранить его в struct Integer и сделать функцию для печати соответствующего структурного целого для стандартного вывода. Программа работает как таковая, но как только она дает результат, она перестает отвечать. Я не получаю никакой прямой ошибки в компиляторе и не могу понять, что не так. Любые другие советы/подсказки, чтобы улучшить стиль программирования также будет очень ценна :)Нужна помощь в отладке кода C

// Header Files Go Here 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

// Function Declarations Go Here 
struct integer * convert_integer(char * stringInt); 
void printer(struct integer * p); 

struct integer { 
    int * arr; 
    int length; 
}; 

// Main Program 
int main() { 
    char * x; 
    x = (char *) malloc(sizeof(char) * 10000); 
    printf("Enter a small string\n"); 
    scanf("%s",x); 
    int j = 0; 
    struct integer * book1; 
    book1 = convert_integer(x); 
    printer(book1); 
    return 0; 
} 

// Function Definitions Go Here 
struct integer * convert_integer(char * stringInt) { 
    struct integer * x = malloc(sizeof(int) * 100); 
    int j = 0; 
    while (stringInt[j] != '\0') { 
     if (stringInt[j] < 48 || stringInt[j] >= 57) { 
      printf("Invalid input. Enter a number "); 
      return; 
     } 
     x->arr[j] = stringInt[j] - 48; 
     j++; 
    } 
    x->length = j; 
    printf("\n the length is %d\n", x->length); 
    return x; 
} 

void printer(struct integer * p) { 
    int j = 0; 
    while (j < p->length) { 
     printf("%d", p->arr[j]); 
     j++; 
    } 
} 
+0

Гораздо лучшее решение для использования динамического массива: используйте стек и реализуйте его со связанным списком. Разум бы вы всегда интересовались только одной цифрой за раз. –

+0

@JacobPollack, справедливо, я сделаю это в ближайшее время. Но я думаю, что важно понять, почему я столкнулся с такой ошибкой :) –

ответ

2

Я добавляю этот ответ, потому что NPE не было достаточно ясно.


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

struct integer* x= malloc(sizeof(int) * 100); 

... но это неверно. Вы запрашиваете слишком много байтов памяти для x, учитывая его тип данных (ничего действительно не так), однако вы не запрашиваете блоки памяти для arr. Она должна выглядеть следующим образом: (? В вашем случае 100)

struct integer *x = malloc(sizeof(struct integer)); 

x->arr = malloc(sizeof(int) * c); 

... где c некоторая константа. Удостоверьтесь, что когда вы free этой структуры вы сначала freearr, а затем free структуры, иначе у вас будет утечка памяти.

Что-то еще я заметил, что вы не делаете, всегда проверяйте результат системного вызова. Вы не проверяете, возвращает ли malloc недопустимый блок памяти.

+0

Раньше я думал, что если я назначу память структуры, я бы автоматически назначил память для сохраненных в ней памяти. Который не имеет смысла, что я думаю об этом сейчас. Большое спасибо за вашу помощь :) Теперь я добавлю тестовый отчет для всех моих маллоков! –

+0

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

+0

Да. Я попробовал, но cudnt upvote cuz i m new, и у меня пока нет репутации. У меня есть закладки и будет повышаться, как только у меня будет возможность сделать это :) –

0

Вы должны добавить прототип для printer сверху. if заявление проверки количества должно быть

if(stringInt[j]<48 || stringInt[j]>57) // > instead of >= 

Это будет иметь больше смысла писать это как

if (stringInt[j] < '0' || stringInt[j] > '9') 

Если вы знаете о isdigit функции, вы можете использовать это, как хорошо.

Вы выделяете память для строки с 10000 символами. Это кажется излишним. Вы можете выделить память на 256 символов, и это должно быть много. Вы также должны освободить память перед выполнением return с помощью оператора free (x);

Вам нужно выделить место для arr внутри функции convert_integer. Ваши ассигнования должны быть:

struct integer* x= malloc(sizeof(integer)); x->arr = malloc (sizeof(int) * 256); 
+0

Спасибо за это :). Я сделал 10000, потому что в конце концов я хотел бы протестировать свою программу на более крупном входе. Они были полезны, но не действительно решают мою проблему. –

0

Здесь:

struct integer* x= malloc(sizeof(int) * 100);; 

распределение памяти для структуры (то есть указателя и целого), но не для массива.

В тот момент, когда вы пытаетесь назначить x->arr[j], у вас есть undefined behaviour.

+0

нет среды, где для 'struct integer' потребуется больше, чем n * 100 байтов (где n обычно 4 или 8), оно состоит только из указателя и целого числа. Он выделяет больше памяти, чем нужно, но это не должно быть актуальной проблемой. –

+0

@JacobPollack: структура содержит указатель. – wildplasser

+0

@wildplasser, это все еще не проблема. Я вижу, что NPE получает, хотя он говорит, что он должен также «malloc» блок памяти достаточного размера для 'arr'. Но проблема не в той строке, которую он указал, это линия, в которую OP не включал ('malloc'ing блок памяти для' arr'). –

0

Ваш код не удается на линии

x->arr[j]=stringInt[j]-48; 

Причина, как вы выделить свою часть памяти:

struct integer* x= malloc(sizeof(int) * 100); 

Это выделяет кусочек n*100 байтов и хранит указатель что ломтик в x. То, что вы хотите сделать, это следующее:

struct integer *x = malloc(sizeof(*x)); 
x->arr = malloc(sizeof(int)*100); 

Это выделяет память, необходимую для хранения integer структуры x и выделяет память для хранения 100 целых чисел и присваивает его x->arr. С вашим кодом x->arr не инициализирован и, следовательно, имеет в нем случайные значения (точнее: значения - это те, которые были сохранены в этой ячейке памяти до).

После завершения использования выделенной памяти, вы должны также освободить его:

free(x->arr); 
free(x); 
+0

Большое спасибо. У меня было плохое представление о том, как работают кусочки памяти! –

0

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

struct Integer { 
    unsigned char *array; /* no point storing sign info on each element */ 
    size_t capacity; /* how many we have space for */ 
    size_t count; /* how many we've actually used */ 
    char sign;  /* +1 or -1 */ 
}; 

Я сделал несколько изменений здесь:

  1. вы только хранить одну базовую-10 цифр для каждого элемента в массиве, поэтому char достаточно большой
  2. нет никакого смысла хранить знак вашего целого числа в каждый элемент массива, поэтому я использую unsigned char и сохраняю знак снаружи
  3. делает ваш массив фиксированным размером негибким, а не в духе большого i nteger. Если вы собираетесь вырастить его динамически, делая это для каждого цифра становится дорогой быстро, так что я с помощью амортизируется постоянное время трюка удвоения мощности каждый раза, когда он заполняет

Теперь, прежде чем мы начнем использовать целое число, нам нужно выделить его.Давайте сделаем самую простую вещь сейчас, и начать его с нулевым размером:

struct Integer *alloc_integer() { 
    struct Integer *i = malloc(sizeof(*i)); 
    /* this integer is empty until we use it ... */ 
    i->array = NULL; 
    i->capacity = 0; 
    i->count = 0; 
    i->sign = 1; 
    return i; 
} 

Конечно, это не имеет смысла, если он остается нулевой размер, так что нам нужно каким-то образом, чтобы сделать его больше:

void grow_integer(struct Integer *i, size_t min_size) { 
    /* this check is redundant if we're only called from append_integer */ 
    if (min_size <= i->capacity) return; 
    /* jump to the next power of 2 (ie, we usually double the capacity) */ 
    size_t new_size = i->capacity * 2; 
    while (new_size < min_size) new_size *= 2; 

    unsigned char *new_array = malloc(new_size * sizeof(*new_array)); 
    /* figure out how to cope if we run out of memory */ 

    memcpy(new_array, i->array, i->count * sizeof(*new_array)); 
    free(i->array); 
    i->array = new_array; 
    i->capacity = new_size; 
} 

Теперь мы можем видеть, как добавить одно целое число:

void append_integer(struct Integer *i, char digit) { 
    if (i->count == i->capacity) 
     grow_integer(i, i->capacity + 1); 
    i->array[ i->count++ ] = (unsigned char)digit; 
} 

(обратите внимание, что проверки в grow_integer и append_integer перекрытием немного: Я мог бы устранить одно, но я еще не решил wheth э grow_integer является публичным интерфейсом пока)

наконец, чтение строки должно быть довольно просто:

struct Integer *str_to_Integer(const char *str) { 
    struct Integer *i = alloc_integer(); 
    for (; *str; ++str) { 
     if (!isdigit(*str)) { 
      free_integer(i); 
      return NULL; 
     } 
     append_integer(i, *str - '0'); 
    } 
    return i; 
} 

Обратите внимание, что я использую isdigit и предпочитают '0' к 48, потому что я не думаю, что есть какая-либо реальная выгоду в принуждении людей запоминать значения кода ASCII, когда компилятор может сделать это за вас.

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