I have the following code (from K&R Exercise 2-4):
#include <stdio.h>
#define MAXLINE 1000 /* maximum input line size */
void squeeze(char s1[], char s2[]);
/* Exercise 2-4. Write an alternate version of squeeze(s1,s2) that deletes each
character in s1 that matches any character in the string s2. */
main()
{
int c, i;
char line[MAXLINE]; /* current input line */
int len = 0; /* current line length */
char s2[MAXLINE]; /* array of characters to delete */
printf("Characters to delete: ");
for (i = 0; (c = getchar()) != '\n'; i)
s2[i] = c;
while ((c = getchar()) != EOF) {
if (c == '\n') {
squeeze(line, s2);
printf("%s\n", line);
for (i = 0; i < len; i)
line[i] = 0;
len = 0;
} else {
line[len] = c;
len;
}
}
return 0;
}
/* squeeze: delete all chars in s2 from s1 */
void squeeze(char s1[], char s2[])
{
int i, j, k;
for (k = 0; s2[k] != '\0'; k ) {
for (i = j = 0; s1[i] != '\0'; i )
if (s1[i] != s2[k])
s1[j ] = s1[i];
s1[j] = '\0';
}
}
But when I run it and it reads in input, I find that there are garbage characters at the end of s2
. Adding the following code after declaring the character arrays:
for (i = 0; i < MAXLINE; i)
line[i] = s2[i] = 0;
seems to fix the issue. But don't character arrays come initialized with 0 to begin with? Does anyone know why this is happening?
CodePudding user response:
The problem here is your strings are not null terminated. Local variables (like line
and s2
) are not automatically initialized with 0. Their content is indeterminate.
Declare line
and s2
like this:
char line[MAXLINE] = { 0 }; // initializes all elements of line with 0
char s2[MAXLINE] = {0}; // initializes all elements of s2 with 0
or just null terminate line
:
...
if (c == '\n') {
line[len] = 0; // <<< add this: null termninate line
squeeze(line, s2);
...
and null terminate s2
:
...
printf("Characters to delete: ");
for (i = 0; (c = getchar()) != '\n'; i)
s2[i] = c;
s2[i] = 0; // <<< add this: null termninate s2
while ((c = getchar()) != EOF) {
...
CodePudding user response:
For starters according to the C Standard the function main without parameters shall be declared like
int main( void )
As the function squeze
accepts two arrays without their length than it means that the arrays contain strings: sequences of characters terminated by zero character '\0'
.
As the second array is not changed within the function then the second parameter should be declared with the qualifier const
.
The function declaration will look like
char * squeeze( char s1[], const char s2[] );
Within the function you should check at first whether s1 or s2 contains an empty string.
The function definition can look for example the following way
char * squeeze( char s1[], const char s2[] )
{
if ( *s1 != '\0' && *s2 != '\0' )
{
size_t i = 0;
for ( size_t j = 0; s1[j] != '\0'; j )
{
size_t k = 0;
while ( s2[k] != '\0' && s2[k] != s1[j] ) k;
if ( s2[k] == '\0' )
{
if ( i != j ) s1[i] = s1[j];
i;
}
}
s1[i] = '\0';
}
return s1;
}
The nested loops within the function
if ( *s1 != '\0' && *s2 != '\0' )
{
size_t i = 0;
for ( size_t j = 0; s1[j] != '\0'; j )
{
size_t k = 0;
while ( s2[k] != '\0' && s2[k] != s1[j] ) k;
if ( s2[k] == '\0' )
{
if ( i != j ) s1[i] = s1[j];
i;
}
}
s1[i] = '\0';
}
can be also rewritten the following way
if ( *s1 != '\0' && *s2 != '\0' )
{
size_t i = 0;
for ( size_t j = 0; s1[j] != '\0'; j )
{
if ( strchr( s2, s1[j] ) == NULL )
{
if ( i != j ) s1[i] = s1[j];
i;
}
}
s1[i] = '\0';
}
In main you need to append entered sequence with the terminating zero character as for example
i = 0;
while ( i 1 < MAXLINE && ( c = getchar() ) != EOF && c != '\n' )
{
s2[i ] = c;
}
s2[i] = '\0';
and
i = 0;
while ( ( c = getchar() ) != EOF )
{
if ( i 1 == MAXLINE || c == '\n' )
{
line[i] = '\0';
printf( "%s\n", squeeze( line, s2 ) );
i = 0;
}
else
{
line[i ] = c;
}
}