在下面的代码中,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;
}
答案 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语句是一个很好的策略。它们占用一行,但要确保你在正确的位置编码。)记住,指令是“得到最大长度,而不是最大字符串。