Char Array终身自身(K& R1-16& 1-17)

时间:2013-10-03 20:03:34

标签: c arrays char

在下面的代码中,char数组在位置1和2处最多打印100个字符,但在位置3处仅打印22.这种行为的原因是什么?

#include<stdio.h>
/* print the longest input line */
/*Exercise 1-16. Revise the main routine of the longest-line program so it will correctly print the length of arbitrary long input lines, and as much as possible of the text.*/

#define MAXLENGTH 100

int mygetline(char s[], int limit);
void charcopy(char to[], char from[]);

int main(){
  char current[MAXLENGTH];
  char longest[MAXLENGTH];
  int curlen;
  int maxlen;

  maxlen = 0;
  while( (curlen = mygetline(current, MAXLENGTH)) > 0 ){
    if (curlen > 80)
      printf("\nvery long:%d; %s\n", curlen, current);//#1# prints 100 digits
    if(curlen>maxlen){
      maxlen=curlen;
      charcopy(longest, current);
      printf("\nlonger:%d; %s\n", maxlen, longest);//#2# prints 100 digits
    }
  }
  if (maxlen)//char array seems to truncates itself at scope boundry.
    printf("\nlongest:%d; %s\n", maxlen, longest);//#3# prints 22 digits
  printf("\nall done!\n");
  return 0;
}

int mygetline(char s[], int limit){
  int i, c;
  for(i=0; i < limit-1 && ((c=getchar()) != EOF) && c != '\n'; ++i)
    s[i]=c;
  if(c=='\n'){
    s[i]=c;
    ++i;}
  else
    if(i >= limit-1)
      while (((c=getchar()) != EOF) && c != '\n')
    ++i;
  s[i]='\0';
  return i-1;
}


void charcopy(char to[], char from[]){
  int i;
  i=0;
  while( (to[i] = from[i])  != '\0'){
    ++i;}
}

它在评论中标记为3的位置仅打印22个字符而不是完整的100个。这非常奇怪。

编辑: 根据Scotts的回答,我已将mygetline更改为:

int mygetline(char s[], int limit){
  int i, c, k;
  for(i=0; i < limit-1 && ((c=getchar()) != EOF) && c != '\n'; ++i)
    s[i]=c;
  if((c=='\n') && (i < limit -1)){
    s[i]=c;
    ++i;}
  else{//if we are over the limit, just store the num of char entered without storing chars
    k = 0;
    while (((c=getchar()) != EOF) && c != '\n')
      ++k;}
  s[i]='\0';
  return i+k;
}

可以看出,如果输入超调限制,则输入的字符数将存储在全新变量k中,该变量不接触数组。我仍然截断了最后一条打印线,我得到了奇怪的32770作为线长。为什么?可以看出,阵列正在婴儿坐着,娇宠,只喂食精确数量的炭,而不是更多。

编辑:第一个列表的问题是,正如斯科特所指出的那样,我正在超越阵列。第二个mygetline的问题是k=0;在if else嵌套中的初始化方式。向上移动初始化并使其成为整个函数的全局,似乎解决了第二个问题。

按如下方式使用mygetline:

int mygetline(char s[], int limit){
  int i, c, k;
  k=0;
  for(i=0; i < limit-1 && ((c=getchar()) != EOF) && c != '\n'; ++i)
    s[i]=c;
  if((c=='\n') && (i < limit -1)){
    s[i]=c;
    ++i;}
  else{//if we are over the limit, just add the num of char entered without storing chars
    while (((c=getchar()) != EOF) && c != '\n')
      ++k;}
  s[i]='\0';
  return i+k;
}

1 个答案:

答案 0 :(得分:1)

好的,所以你需要了解的关于C的事情是它根本不会照顾你。如果您有一个声明为char foo[4]的数组并尝试写入foo[20],C将不会抱怨。 (如果你写入受限制的内存,它通常会抛出分段违规,比如NULL,但如果你有权访问内存,你可以做任何你想做的事。)

那么,当您写入数组时,会发生什么呢?官方的答案是“未定义的行为” - 一个完全通用的全面答案,并说,“这取决于编译器。”但是,在大多数C编译器中,它会执行一个叫做损坏堆栈的东西。

你在任何函数中要求的内存 - 包括main - 都是在一个很好的单个相干块中分配的。所以在你的main函数中,current有100个字节,longest有100个字节,curlen有4个字节,maxlen有4个字节(假设是32位整数)。它们也可能是64 - 再次,取决于编译器。)如果你写current[123],C将允许你这样做 - 它会把你写的任何内容放在longest[23]的位置。 (通常。再次,它在技术上是未定义的行为,所以不能保证会发生这种情况。)

您的问题是mygetline中设置s[i] = '\0';的行。问题是,你让i变得比数组大。如果您printf("i = %d\n", i);就在该行之前,您会看到i = 123.您的最后一行没有您最大的那一行那么大,所以您要覆盖longest中您不知道的数据我想覆盖。

有很多方法可以解决这个问题。即,确保当您将某些内容设置为“\ 0”时,请确保i <= limit - 1。 (您可以将s[i] = '\0'行移至while !EOF行上方并将其设置为s[limit - 1],以确保不会过去。您还需要添加{}到你的if语句。通常,将它们添加到任何if或while语句是一个很好的策略。它们占用一行,但要确保你在正确的位置编码。)记住,指令是“得到最大长度,而不是最大字符串。

如果你实际上在前两行中看到100个字符,我会感到惊讶。据我所知,你应该看到122.