Reputation: 13
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;
}
Upvotes: 0
Views: 134
Reputation: 15397
Ok, so the thing you need to know about C is that it doesn't babysit you at all. If you have an array declared as char foo[4]
and try writing to foo[20]
, C won't complain at all. (It will typically throw a segmentation violation if you write into restricted memory, like NULL, but if you have access to the memory, you can do whatever you want to it.)
So, what happens, when you write to an array, further than you should? The official answer is "undefined behavior" - a blanket answer that is totally generic, and says, "It's up to the compiler." However, in most C compilers, it will do something called corrupting your stack.
The memory you ask for in any function - including main - is all allocated in a nice single coherent block. So in your main function, you have 100 bytes for current
, 100 bytes for longest
, 4 bytes for curlen
and 4 bytes for maxlen
(assuming 32-bit integers. They may also be 64 - again, depends on the compiler.) If you write to current[123]
, C will let you do it - and it will put whatever you wrote in the place of longest[23]
. (Usually. Again, it's technically undefined behavior, so it's not guaranteed this will happen.)
Your problem is the line in mygetline
where you set s[i] = '\0';
. The problem is, you've let i
get bigger than the array. If you printf("i = %d\n", i);
right before that line, you'll see that i = 123. Your last line is not as big as your biggest line, so you're overwriting the data in longest
that you don't want to overwrite.
There are lots of ways to fix this. Namely, make sure that when you set something to '\0', make sure that i <= limit - 1
. (You can do this by moving the s[i] = '\0'
line to above your while !EOF
line and setting it to s[limit - 1]
just to make sure you don't go over. You'll also need to add {} to your if statement. Generally, it's a good policy to add them to any if or while statement. They take up a line, but make sure you're coding in the right place.) Remember, the instruction is to "get the maximum length, not the maximum string.`
I'd be surprised if you're actually seeing 100 characters in the first 2 lines. From what I can tell, you should be seeing 122.
Upvotes: 1