-10

I'm wondering why printf() when provided an array and no formatting options, successfully prints character arrays but while using integer arrays the compiler throws a warning and a garbage value is printed.

Here's my code:

#include <stdio.h>

int main()
{
   char cr[3] = { 'a', 'b' };
   int ar[3] = { 1, 2 };

   printf("character array output using printf() : ");
   printf(cr);

   printf("\n\nInteger array output using printf() : ");
   printf(ar);
   printf("\n");

   return 0;
}

and here's my output:

../main.c: In function ‘main’:
../main.c:12:4: warning: passing argument 1 of ‘printf’ from incompatible pointer type [enabled by default]
    printf(ar);
    ^
In file included from ../main.c:1:0:
/usr/include/stdio.h:362:12: note: expected ‘const char * restrict’ but argument is of type ‘int *’
 extern int printf (const char *__restrict __format, ...);
            ^
Finished building: ../main.c
Andre Kampling
  • 5,476
  • 2
  • 20
  • 47
RaJ
  • 129
  • 8
  • 5
    Better question: Why are you sending `int*` to a function that expects `const char*` as its first argument ? That warning is there for a reason. [**`printf`**](http://en.cppreference.com/w/c/io/fprintf) expects you to live up to its requirements, and you're not. – WhozCraig Sep 08 '17 at 07:29
  • 5
    Rather than showing images copy and paste code and output as code formatted text here. – Andre Kampling Sep 08 '17 at 07:31
  • 4
    It seems you should take some time to [read a good beginners book](http://stackoverflow.com/questions/562303/the-definitive-c-book-guide-and-list). You are doing two very wrong things, both leading to [*undefined behavior*](https://en.wikipedia.org/wiki/Undefined_behavior) which means your program is *ill-formed* an invalid. – Some programmer dude Sep 08 '17 at 07:31
  • 3
    Please **edit your question**. Text (code and output) should be given as formatted text with four spaces at start of every line. You don't need images in your question, and you should remove them (replacing them with text) – Basile Starynkevitch Sep 08 '17 at 07:31
  • Read about [int printf( **const char*** format, ... );](http://en.cppreference.com/w/cpp/io/c/fprintf) which takes a **`const char*`** as 1st parameter and **not** `const int*`. – Andre Kampling Sep 08 '17 at 07:32
  • 2
    BTW [ar(1)](http://man7.org/linux/man-pages/man1/ar.1.html) is a usual command, so dont name your program like this. – Basile Starynkevitch Sep 08 '17 at 07:34
  • 2
    And compile your code with all warnings and debug info, i.e `gcc -Wall -Wextra -g ar.c -o myar` – Basile Starynkevitch Sep 08 '17 at 07:37
  • 1
    What did your compiler tell you? – Jabberwocky Sep 08 '17 at 07:42
  • 1
    You also declare arrays with a size of 3 and initialize only 2 elements... – Math Lover Sep 08 '17 at 10:00
  • and to all others who take turns and try to discourage the user, you all can either do some research and answer the question or if you don't know the answer, don't comment at all. and I feel my question is valid. – RaJ Sep 08 '17 at 10:02
  • I felt bad for you for a minute. Thanks for correcting me. –  Sep 08 '17 at 13:25

3 Answers3

3

The C language standard declares printf as follows:

int printf(const char *format, ...);

It returns an integer and takes a first parameter of a pointer to a constant character and an arbitrary number of subsequent parameters of arbitrary type.

yajiv
  • 2,901
  • 2
  • 15
  • 25
  • For completeness: His/her `cr[3]` array will be initialized to: `{ 'a' , 'b', '\0'} ` becaue the last memory place is implicitly zero initialized. That means the OP has got a null terminated string `"ab"` here although he/she initialized with `{ 'a', 'b' }`. – Andre Kampling Sep 08 '17 at 07:42
  • @AndreKampling *"the last memory place is implicitly zero initialized"* this is news for me, is that part of the C standard or an implementation detail of some compiler? – Patrick Trentin Sep 08 '17 at 08:01
  • 1
    @PatrickTrentin: Missing elements in an initializer list are zero initialized which is showed here: [How to initialize all members of an array to the same value?](https://stackoverflow.com/a/201116/8051589) as the OP used `cr[3] = { 'a', 'b' }`. – Andre Kampling Sep 08 '17 at 08:02
3

To answer what exactly happens I want firstly show what your array initializations do. Your array initializer lists are incomplete, there are missing elements as the size is greater than the list. That will result in zero initialization for the missing elements.

1. char cr[3] array:

char cr[3] = { 'a', 'b' };

will lead to:

     character represantation      ==       decimal representation
-+----+----+----+----+----+----+-      -+----+----+----+----+----+----+-
 |    | a  | b  | \0 |    |    |        |    | 97 | 98 | 0  |    |    | 
-+----+----+----+----+----+----+-      -+----+----+----+----+----+----+-
       ^~~~                                   ^~~~
       | char                                 | char
       cr                                     cr

The printf() function is defined as: int printf( const char* format, ... );. That means it takes a char pointer and doesn't change the elements that are pointed to.

If you now pass the cr array to the printf() function the array name will decay to a pointer. The printf() function interprets the format parameter as null terminated character array which is called a C-string. Your cr array is a null terminated C-string as it consists of { 'a', 'b', '\0' }. That means the printf() function can successfully print the string "ab" to stdout.

2. int ar[3] array:

int ar[3] = { 1, 2 };

will lead to:

-+----+----+----+----+----+----+-
 |    | 1  | 2  | 0  |    |    | 
-+----+----+----+----+----+----+-
       ^~~~
       | int
       ar

For now you see no great difference (just type and content) in contrast to the 1st case. But now you're passing the ar array to the printf() function. The array name will decay to an int* and is implicitly casted to const char* (this will bring you the compiler warning you've got). If the printf() function now dereferences the memory it looks like the following (assuming that an int consists of 4 bytes and your machine uses little endian memory representation):

-+----+----+----+----+----+----+----+----+----+----+----+----+----+-
 |    | 1  | 0  | 0  | 0  | 2  | 0  | 0  | 0  | 0  | 0  | 0  | 0  | 
-+----+----+----+----+----+----+----+----+----+----+----+----+----+-
       ^~~~~~~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~
       |                int                 int                  int
       ^~~~ ^~~~ ^~~~ ^~~~ ^~~~ ^~~~ ^~~~ ^~~~ ^~~~ ^~~~ ^~~~ ^~~~
       | char char char char char char char char char char char char
       ar

Instead of getting a string like "12" printed it will consume the both left characters that are the decimal value 1 and 0 (null terminator), see diagram above. The remaining decimal values after 1 and 0 are not recognized as they are after the null terminator. Assuming your machine uses the ASCII table the decimal 1 is not a printable character leading to a garbage value printed.


Proof of concept:

To prove what I write before you can use the following function which takes the same 1st argument as printf(), namely const char*:

void printhexchars(const char* str)
{
   while(*str)
   {
      printf("%03d ", *(str++));
   }
   /* print last character after while loop: '\0' */
   printf("%03d ", *str);
}

This functions prints the integer representation of a null terminated C-string. See example with your arrays char cr[3] and int ar[3] on ideone.com. Of course passing the integer array to the function above will generate the same compiler warning as you already get before.

Output:

character array output using printf() : 097 098 000 

Integer array output using printf() : 001 000

As you can see you get 097 098 000 which is "ab" for your character array.
Your integer array leads to 001 000 which leads to the non printable character with a decimal value of 1.

Andre Kampling
  • 5,476
  • 2
  • 20
  • 47
  • this is what i was looking for :- " Instead of getting "12" printed it will print the character that have the decimal value 1 and after that the null terminator. Assuming your machine uses the ASCII table the decimal 1 is not a printable character leading to garbage values printed " . – RaJ Sep 08 '17 at 09:31
  • @RaJ: I've added a little proof of concept, please have a look at it. – Andre Kampling Sep 11 '17 at 07:12
0

Because the both array as display as character and the chars are keep as ascii code and integers are kept as integer (thanks cpt. obvious). Printf interprets the input as code ascii so in case of integers you have control character which are not very understandable.

kappj
  • 17
  • 2