I am learning through K&R book and doing an exercise where I'm supposed to copy one array into another with minor changes (converting escape strings into the actual signs and letters) using a switch function escape(from,to).
It seems that I did it alright, but what is puzzling me is that the array (from) is being changed as well into a few letters. I was wondering why is this happening and if am I not informed enough about switch or something else?
#include <stdio.h>
#include <stdlib.h>
#define MAX 250
int main()
{
char ar1[MAX];
char ar2[MAX];
int c;
int i = 0;
while((c = getchar()) != EOF)
{
if ( i < MAX - 1 ){
ar1[i] = c;
i ;}
else
ar1[i ] = '\0';
}
escape(ar1,ar2);
printf("%s",ar2);
printf("%s",ar1);
return 0;
}
escape(char s[],char t[])
{
int i = 0;
int j = 0;
while (i < MAX )
{
switch(s[i])
{
case '\n':
t[j] = '\\';
j ;
t[j ] = 'n';
i ;
break;
default:
t[j] = s[i];
i ;
j ;
break;
}
}
t[j] = '\0';
}
CodePudding user response:
K&R is outdated, as is the version of C found inside it, called C90. This old version allowed various language flaws like "implicit int" and "no prototype functions". What happens in this old version when you type escape(ar1,ar2); with no prior function declaration visible, is that the compiler "takes a chance" at the types used - specifically it assumes that everything has type int.
In your case the C90 compiler find's the call escape(ar1,ar2); then goes: "Oh boy what's escape, never heard of it before. It's probably an int escape (int, int) function, right? Lets do that and see if there will be fireworks".
While in reality it should have been void escape (char s[],char t[]) for your program to function as intended.
Similarly, when you type escape(char s[],char t[]) then it is implicitly assumed that this function returns int, which is not what you want.
You can get rid of all these problems by updating to the current standard C and also find a less outdated book. In standard C, your code isn't allowed to compile and there will be no strange surprises.
Regardless of C version, you can fix the problem by providing a prototype-format (types present) function declaration:
void escape (char s[], char t[]); // function declaration, prototype format
int main()
{
...
}
void escape (char s[], char t[]) // function definition
{
...
}
CodePudding user response:
The loop in your escape function will always overrun the bounds of the output array. Even if there are no newlines to escape, the final t[j] = '\0'; will do that because you unconditionally run MAX iterations of the loop and therefore increment j at least MAX times. Undefined behavior results, of which unexpected modifications to other variables is one reasonably common manifestation.
You structure the input array as a string, so probably escape should stop converting data when it reaches the string terminator. To be completely safe, however, it must also be sure terminate when it fills up the output array if it does that before processing all the input (and don't forget to leave room for the output's string terminator).
