C环不会退出

问题描述:

早上好! 事后看来,这将成为这些令人眼花缭乱的问题之一,但对于我来说,我很难过。我正在经历C编程语言中的一些练习,并且我设法编写了一些代码来初始化一个循环。在谷歌搜索之后,我找到了将循环初始化为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 Till 2012-03-24 12:22:04

+1

声明“int histogram [50] = {0}'后缺少分号。既然你已经在声明中初始化了'直方图',你不需要在循环中重做,它应该检查'c 2012-03-24 12:23:08

+0

永不回收变量。尽可能将它们的范围设置为本地(小),并在需要时声明新范围。无论如何编译器会优化这个。 – bitmask 2012-03-24 12:29:54

这是因为histogram[c] = 0写过去histogram内存时c = 50。所以基本上histogram[50]覆盖c和使它0

这是因为阵列从0开始C.所以50元件阵列中的最后一个有效索引是49

从技术上讲,虽然有趣和可利用,你不能依赖于此。这是未定义行为的表现。内存可以很容易地有另一种布局,导致事情“正常工作”或做更有趣的事情。

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 2012-03-24 12:43:42

+0

@Caleb:在C中,一个'const int'定义创建一个只读对象,而不是一个常量。有时候你真的需要一个常量:'sizeof arr/sizeof * arr'就是这样一个常量。 – pmg 2012-03-24 12:47:22

+0

无论哪种方式,您都会得到相同的号码。如果您使用sizeof数学,您仍然必须在某处指定数组大小。所以,你可以给这个值赋一个名字,说'int histogram [histogram_size];'声明'histogram',或者你可以说'int histogram [50];'。我认为前者更好地解决了你提出的“魔术常数”问题。 – Caleb 2012-03-24 13:01:54

您正在以直方图访问元素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预处理程序语句,将在编译之前进行处理。对于编译器来说,它看起来好像你已经在任何使用HISTOGRAM_SIZE的地方编写了50个,所以你不会得到额外的开销。

'const int'给你一个类似的解决方案,它在很多情况下会给出与定义相同的结果(我不是100%确定在哪些情况下,其他人可以*阐述),但也会给你额外的类型检查奖励。

+1

在C89中,const int定义没有定义数组维中可用的常量(它定义了一个只读对象)。 C99允许不需要常量的VLAs(可变长度数组)来指定大小。 – pmg 2012-03-24 12:36:29

+0

啊,谢谢!我已经编辑了上述内容来反映这一点。 – sonicwave 2012-03-24 12:43:01