Xiao Han Xiao Han - 1 day ago 5
C Question

Why does the program print out an "@" when I enter nothing?

I wrote a program in order to reverse a string. However, when I enter nothing but press the "enter" key, it prints out an "@".

The code is as follows:


#include <stdio.h>
#include <string.h>
int main(void)
{
int i, j, temp;
char str[80];

scanf("%[^\n]s", str);
i = strlen(str);
//printf("%d\n", i);
//printf("%d\n", sizeof(str));
for (j=0; j<i/2; j++) {
temp=str[i-j-1];
str[i-j-1]=str[j];
str[j]=temp;
}
for(i = 0; str[i] != 0; i++)
putchar(str[i]);
}


I tried to use
printf()
function to see what happens when I press the "Enter" key.

However, after adding
printf("%d\n", i);
, the output became "3 @".

After adding
printf("%d\n", sizeof(str));
, the output became "0 80".

It seemed as if "sizeof" had automatically "fixed" the problem.

My roommate said that the problem may result from initialization. I tried to change the code
char str[80]
to
char str[80] = {0}
, and everything works well. But I still don't understand what "sizeof" does when it exists in the code. If it really results in the initialization, why will such thing happen when the program runs line by line?

Answer

When you declare an array without initializing any part of the array, you receive a pointer to a memory location that has not been initialized. That memory location could contain anything. In fact, you're lucky it stopped just at the @.

By specifying char str[80] = {0} you are effectively saying:

char str[80] = {0, 0, 0, /* 77 more times */ };

Thereby initializing the string to all null values. This is because the compiler automatically pads arrays with nulls if it is partially initialized. (However, this is not the case when you allocate memory from the heap, just a warning).

To understand why everything was happening, let's follow through your code.

When you set i to the value returned by strlen(str), strlen iterates over the location starting at the memory location pointed to by str. Since your memory is not initialized, it finds a @ at location 0 and then 0 at location 1, so it correctly returns 1.

What happens with the loops when you don't enter anything? i is set to 0, j is set to 0, so the condition j<i/2 evaluates to 0<0, which is false so it moves on to the second condition. The second condition only tests if the current location in the array is null. Coincidentally you are returned a memory location where the first char is @. It prints it and luckily the next value is null.

When you use the sizeof operator, you are receiving the size of the entire array that you were allocated on the stack (this is important you you may run into this issue later if you start using pointers). If you used strlen, you would have received 1 instead.

Suggestions

Instead of trying to do i = strlen(str);, I would suggest doing i = scanf("%[^\n]s", str);. This is because scanf returns the number of chars read and placed in the buffer. Also, try to use more descriptive variable names, it makes reading code so much easier.

Comments