0

In the following code, the char array prints up to 100 characters at location 1 and 2 but at location 3 it only prints 22. What is the reason for this behavior?

#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;}
}

Its the location marked 3 in comment that prints only 22 characters instead of the full 100. Its very weird.

Edit: As per Scotts answer, i have changed mygetline to this:

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;
}

As can be seen, if input overshoots limit, then num of characters entered is stored in entirely new variable, k which does not touch the array. I still get truncation of the last printed line and i get weird 32770 as line lengths.Why? As can be seen, array is being baby sat and coddled and fed just the precise amount of char and no more.

Edit: The problem with the first listing was, as pointed out by Scott was that i was overshooting arrays. The problem with the second mygetline was that k=0; was initialized way way inside the if else nest. Moving the initialization upwards and making it global to the whole function, seems to solve the second issue.

working mygetline as follows:

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;
}
4

1 回答 1

1

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

那么,当您写入数组时,会发生什么情况?官方的回答是“未定义的行为”——一个完全通用的笼统回答,并说,“这取决于编译器。” 然而,在大多数 C 编译器中,它会做一些叫做破坏你的堆栈的事情。

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

您的问题是mygetline您设置的行s[i] = '\0';。问题是,你让iget 比数组更大。如果您printf("i = %d\n", i);在该行之前,您会看到 i = 123。您的最后一行没有最大的行那么大,因此您正在覆盖longest您不想覆盖的数据。

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

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

于 2013-10-03T20:57:59.373 回答