2012-03-24 5 views
0

Доброе утро, и все! В конце концов, это станет одним из таких ослепительно-простых вопросов, но для меня жизнь в тупике. Я выполняю некоторые упражнения на языке программирования C, и мне удалось написать некоторый код для инициализации цикла. После некоторого Googling я нашел лучшие способы инициализации цикла до 0, но я не понимаю, почему цикл, который я написал для этого, не заканчивается. Я использовал отладчик, чтобы узнать, что это потому, что переменная «c» никогда не достигает 50, она доходит до 49, а затем перекатывается до 0, но я не могу понять, почему она перевернулась. Код прилагается ниже, кто-нибудь знает, что здесь происходит?C петля не выйдет

#include <stdio.h> 
#define IN 1 
#define OUT 0 

/* Write a program to print a histogram of the lengths of words in 
    itsinput. */ 
main() 
{ 
    int c=0; 
    int histogram[50]={0} 
    int current_length=0; 
    int state=OUT; 

    //Here we borrow C so we don't have to use i 
    printf("Initializing...\n"); 
    while(c<51){ 
     histogram[c] =0; 
     c=c+1; 
    } 
    c=0; 
    printf("Done\n"); 

    while((c=getchar()) != EOF){ 
     if((c==32 || c==10) && state==IN){ 
      //End of word 
      state=OUT; 
      histogram[current_length++]; 
     }else if((c>=33 && c<=126) && state==OUT){ 
      //Start of word 
      state=IN; 
      current_length=0; 
     }else if((c>=33 && c<=126) && state==IN){ 
      //In a word 
      current_length++; 
     } else { 
      //Not in a word 
      //Example, " " or " \n " 
      ; 
     } 
    } 

    //Print the histogram 
    //Recycle current_length to hold the length of the longest word 
    //Find longest word 
    for(c=0; c<50; c++){ 
     if(c>histogram[c]) 
      current_length=histogram[c]; 
    } 
    for(c=current_length; c>=0; c--){ 
     for(state=0; state<=50; state++){ 
      if(histogram[c]>=current_length) 
       printf("_"); 
      else 
       printf(" "); 
     } 
    } 
} 
+1

Обратите внимание на эту строку: 'while (c <51)'! – Till

+1

Точка с запятой отсутствует после объявления 'int histogram [50] = {0}'. Поскольку вы инициализировали 'histogram' в объявлении, вам не нужно делать это снова в цикле, который должен проверять' c <50', а не 'c <51'. –

+0

Никогда не перерабатывайте переменные. Сделайте свой охват локальным (маленьким), насколько это возможно, и объявите новые, когда это необходимо. Компилятор все равно оптимизирует это. – bitmask

ответ

5

Это потому, что histogram[c] = 0 пишет мимо histogram памяти при c = 50. Таким образом, по существу histogram[50] переписывает с и делает его 0.

Это происходит потому, что массивы начинаются с 0 в C. Так последний действительный индекс в массиве 50-элементного составляет 49.

Технически, хотя интересно и полезно использовать, вы не можете положиться на это. Это проявление неопределенного поведения. Память может легко иметь другой макет, который заставляет вещи «просто работать» или делать что-то смешное.

1

histogram имеет 50 элементов: от индекса 0 до индекса 49.
Вы пытаетесь написать индекс 50. все ставки выключены

сделать

while (c < 50) 

или, чтобы избежать магии константы

while (c < sizeof histogram/sizeof *histogram) 
+0

Не все константы - это волшебство. Простой 'const int histogram_size = 50;' будет работать, и (IMO) будет более читаемым, чем 'sizeof histogram/sizeof * histogram'. – Caleb

+0

@Caleb: в C определение 'const int 'создает объект только для чтения, а не константу. Иногда вам действительно нужна константа: 'sizeof arr/sizeof * arr' - такая константа. – pmg

+0

Вы получаете тот же номер в любом случае. Если вы используете математику sizeof, вам все равно нужно указать размер массива. Таким образом, вы можете присвоить имя значению и сказать 'int histogram [histogram_size];' объявить 'histogram', или вы можете сказать' int histogram [50]; '. Я думаю, что бывший лучше решает проблему «магической константы», которую вы подняли. – Caleb

0

Вы получаете доступ к элементам от 0 до 50 в гистограмме, которая содержит только элементы от 0 до 49 (C/C++ использует нуль-индексацию, поэтому максимальный элемент массива всегда будет размером-1).

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

#define HISTOGRAM_SIZE 50 

Или (работает только для C99 или C++, смотрите ниже комментарий):

const int HISTOGRAM_SIZE = 50; 

Тогда:

int histogram[HISTOGRAM_SIZE]; 

И:

while(c<HISTOGRAM_SIZE) 

'#define' - инструкция C-препроцессора и будет обработана перед компиляцией. Для компилятора это будет выглядеть так, как если бы вы написали 50 везде, где используется HISTOGRAM_SIZE, поэтому вы не получите дополнительных накладных расходов.

«const int» дает вам аналогичное решение, которое во многих случаях даст тот же результат, что и с определением (я не уверен на 100%, при каких обстоятельствах, хотя другие могут свободно разрабатывать), но также дают вам дополнительный бонус проверки типов.

+1

В C89 определение 'const int 'не определяет константу, используемую в измерениях массива (она определяет объект только для чтения). C99 позволяет VLA (массивы переменной длины), которые не нуждаются в константах для указания размера. – pmg

+0

А, спасибо! Я отредактировал это, чтобы отразить это. – sonicwave

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