Home > other >  Why do I have garbage characters at the end of my character array?
Why do I have garbage characters at the end of my character array?

Time:02-23

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