Неожиданные результаты при присваивании значений массиву In c - PullRequest
5 голосов
/ 24 декабря 2011

Я читаю C Язык программирования, второе издание .Я пришел к этому упражнению [1-13 в разделе 1.6, стр.24 2nd ed ].

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

Все работает довольно хорошо, я думаю, за исключением случаев, когда я пытаюсь определить, является ли последний счетчик слов (VARIABLE tmp) <= 10 или> 10, затем назначить его соответствующемуиндекс в count [tmp-1] или count [11], если он больше чем.Я даже не беспокоюсь о печати фактической гистограммы, я просто хотел бы сейчас иметь правильное представление массива.Ниже приведен вывод моей программы при запуске.

asdasd 
_________________________________
 1  2  3  4  5  6  7  8  9 10 11 
   (x-axis) Length of words 
---------------------------------
[0 SPACE] [0 NEWLINE] [0 TAB] 
[1 WORD] [0.000 KILOBYTE] [6 CHAR]



6---


ARRAy= 1  1  1  1  1  2  0  0  0  0 

Вот мой код

#include <stdio.h>
#define MAX 10


int main (void) {
    //
    int nc,nw,nt,ns,nl;  //nc = bytes, nw = words, nt = tabs, ns = spaces, nl = newlines
    nc = nw = nt = ns = nl = 0;
    //
    int c;                     //getchar()
    int done = 0;             //don't even know I'm a noob just ignore...
    int tmp = 0;              //last word count (this works well)
    int array[MAX + 1];      //For outputting screen formatters like ---
    int count[11];           //THIS is whats broken random values
    int state = 0;
    int waslast = 0;
    float kbcount = 0;
    for (c = 0; c <= MAX; c++)
    count[c] = 0;

    while (done == 0) {
        c = getchar();
        ++nc;

        if (c == ' ' || c == '\n' || c == '\t') {
            waslast = 1;



            if (c == '\t') {
                ++nt;
                state = tmp;
                tmp = 0;
            }
            else if (c == '\n') {
                ++nl;
                state = tmp;
                tmp = 0;
            }
            else if (c == ' ') {
                ++ns;
                state = tmp;
                tmp = 0;
            }
        }

        if (c == EOF) {
            done = 1;
        }
        else if (c != ' ' && c != '\n' && c != '\t') {
            tmp++;
            state = tmp;
            if (waslast == 1) {
                nw++;
                waslast=0;
            }
            if (nc == 1)
                nw++;
        }

        if (tmp <= 10)
            count[tmp-1]++;       //Completely random assignments
        else
            count[11]++;          //This is broken
    }



    // END WHILE
    //
    //



    printf("\n");
    for (c = 1; c <= MAX + 1; c++) {
        printf("___");

    }

    printf("\n");

    for (c = 1; c <= MAX + 1; c++) {
        array[c] = c;
        printf("%2d ", array[c]);
    }

    printf("\n   (x-axis) Length of words \n");

    for (c = 1; c <= MAX + 1; c++){
        printf("---");
    }

    kbcount = (nc-1)/1024;

    printf("\n[%d SPACE] [%d NEWLINE] [%d TAB] \n[%d WORD] [%.3f KILOBYTE] [%d CHAR]\n\n\n\n%d---\n\n\n",
           ns,nl,nt,nw,kbcount,(nc -(nl+nt+ns))-1,state);

    printf("ARRAy=");
    for (c = 0; c<MAX ;++c)
        printf(" %d ",count[c]);
    return 0;


}

~ ~

Ответы [ 3 ]

10 голосов
/ 24 декабря 2011

c массивы индексируются от 0. count[11]++; выходит за границы массива.

Допустимые индексы для массива из 11 элементов - это индексы от 0 до 10 включительно.11-й элемент в массиве count находится в count[10].

4 голосов
/ 24 декабря 2011

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

  1. Потратьте время, чтобы набрать значимые имена переменных. Или хотя бы усеченные. Как NumTabs или что-то, что соответствует вашему стилю.
  2. Убери свой стиль отступов. Правильный отступ позволяет легче понять ход программы.

Итак, ваша большая явная ошибка, когда вы делаете это:

count[11]++;          //This is broken

В коде он определен выше как:

int count[11];

В этом массиве 11 целых чисел. Однако вы не начинаете ссылаться на них с 1. Вы начинаете ссылаться на них с 0. count [0], count [1] ... count [10] все допустимы. Вот так:

0 1 2 3 4 5 6 7 8 9 10

Как вы можете видеть, это 11 чисел, хотя их число увеличивается только до 10. Если вы хотите иметь возможность доступа к счетчику [11], вы должны объявить счет как

int count[12];

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

В любом случае, если этого было недостаточно, если вы хотите представить это концептуально - это не так, как работает, но концептуально - ваш массив выделяет 11 целых чисел, а 'count' - указатель на него. Таким образом (указатель + 0) будет указывать на 1-е целое число, что то же самое, что сказать указатель [0]. (указатель + 1), что то же самое, что сказать, указатель [1] будет указывать на 2-е целое число. (указатель + 5) / указатель [5] будут указывать на 6-е целое число, (указатель + 11) / указатель [11] на 12-й - которого не существует, поскольку их всего 11.

1 голос
/ 24 декабря 2011

Два Три дополнительные точки (ошибки), которые содержит ваша программа:

  • Деление целых чисел дает результат, который является целым числом, поэтому в:

    float kbcount = (nc-1)/1024;

Переменная kbcount установлена ​​в integer результат целочисленного деления nc - 1 на 1024.

Я полагаю, что вы хотите сказать следующее:

float kbcount = (nc - 1) / 1024.0;

Поскольку одна из частей (знаменатель в данном случае) - это число с плавающей запятой, правиластаршинства преобразует ( повышает ) обе части в значение с плавающей запятой, а затем деление становится делением с плавающей запятой, поэтому результатом будет значение с плавающей запятой с его дробным (десятичным числом)) значение.Прочитайте Раздел 2.7 (стр. 42) языка программирования C, для лучшего объяснения.

Далее

  • Вы можете упростить логику определения, является ли c частью слова или частью «пробела» (пробелы, табуляции, новые строки) для созданияВы программируете короче и легче для понимания.

Например:

enum state_t = {whitespace, printable};
...

enum state_t state = whitespace;
while (EOF != (c = getchar())) {
    bytes++;

    if (is_whitespace(c)) {
        if (state == printable) { /* the whitespace ends the 'word' state */
            count[length % MAX]++;
            length = 0;
        }
        ...
        state = whitespace;
    } else {
        if (state == whitespace) {
            /* starting a new word */
            wordcount++;
        }
        length++ /* word length */
        state = printable;
    }
    ...
    /* anything else you want to do */
}
/* done reading standard input (stdin), now print report... */

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

И, наконец,

  • Вы новичок или новичок, не a noob .

Ссылка:

//don't even know I'm a noob just ignore...

Честно говоря, каждый программист совершает тонн ошибок, когда они начинаются и при изучении нового языка программирования.Но это часть естественного процесса обучения.Вы учитесь, исследуя, пробуя новые вещи, и обнаруживая и то, что работает, а что не .Это процесс, и мы надеемся, что вы сможете насладиться задачами не только придумать решение проблемы, но и разбить решение на логические шаги размером с укус и написать его правильнона синтетическом языке, в данном случае C.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...