Why the code works like this (when a constant is declared as a string):

#include <stdio.h> #include <stdlib.h> #define A "3" int main(void){ puts(A); } 

and no (constant number):

 #include <stdio.h> #include <stdlib.h> #define A 3 int main(void){ puts(A); } 

What needs to be fixed?

    5 answers 5

    man puts informs us that the prototype for puts() is:

     int puts(const char *s); 

    That is, as an argument, this function takes a pointer to char , not a number. If you want to display a number, then printf () with analogues:

     printf( "%d\n", A ); 

    Or translate a number into a string, then output (see man sprintf).

      First, be sure to return the return code from the main function main (), using return(0) or exit(0) .

      Second, puts(A); takes as an argument a string (a pointer to a string), then adds a new string character to this string \n and outputs the whole thing to STDOUT, I mean, on the screen.

      If, instead of a string, you pass a number to puts , then the function will consider this number as an address for a string, as if located at that address. But in fact, an attempt is made to access an arbitrary memory cell, to which, with high probability, the program does not have access. Therefore, the OS will block this attempt and issue an error: Segmentation fault .

      Thirdly, what needs to be fixed? It depends on what you need to get in response. Print the number? For these purposes, as already stated in another answer, printf is suitable. If you really need to use puts , then you need to do a number to string conversion. Alternatively, you can use sprintf.

      • 6
        In modern C (99), returning 0 from main () is implicit, you can not write. - PinkTux

      Your problem is mainly related to your misconception that #define declares a constant. This is not true. Throw away the textbook in which it is written. Or stick your teacher's nose in this text.

      #define is a macro substitution intended to be processed by the preprocessor.

      This constant in C is written as:

       const int alpha = 3; const char beta[]="beta"; 

      The difference is that the macro substitution preprocessor mechanically thrust into all the places in the source text where it is found.

      At the same time, the constant is processed by the compiler, at a higher, "smart" level. Note that a real constant has a type — this means that a stupid error like “number instead of a string” is simply not compiled. But with a macro substitution such a number can not pass.

      One of the important rules is that macro substitutions should always be preferred to constants to avoid wonderful glitches.

      Material about constants

      • @Ilnyr, Одно из важных правил ... is for those who have not mastered the macro. In fact, the general "constants" connect the parts of the system into a single whole namely through the macro in .h files (look in / usr / include) - avp
      • @avp - changed one constant - and ran the whole program to recompile, instead of one object manager. Kilometers of macros are a favorite nonsense of old-school programmers, the mere fact that in Windows almost all system calls — in fact, macros (with replacement for the A and W versions — is crushing, as with music), says a lot. A special piece of macro art is SDL from STM microcontrollers. - gbg
      • So simply it is not necessary to place local constants in the general .h. In general, macros on C sometimes allow you to simply perform miracles. Only, of course, you need to know the measure, and just design the system correctly. - avp

      To sum up, I agree with all the posts, with one amendment. The #define A 3 directive defines a character constant (literal), not a number, as stated above. It (the character constant) becomes a number at the compilation stage (after substituting the macro, the abbreviated name). Those. The const char * prototype part says that the puts() function expects a pointer to immutable data of type char .

      The pointer is variable, while the strings #define A 3 and puts(A) attempt to pass a numeric constant to the puts() function. (By the way, the compiler also says that А an int type). Hence the problem. And it is not necessary to avoid macro substitutions, but to correctly follow the correspondence to the specified typifications.

      PS You can print your value like this printf("%c %d\n", A, A); and admire the strange picture in addition :)

      • Т.е. часть прототипа const char * говорит о том, что функция puts() ожидает указатель на неизменяемые данные типа char Т.е. часть прототипа const char * говорит о том, что функция puts() ожидает указатель на неизменяемые данные типа char — rather, the const char * says that puts() will not change this data. - avp
      • Since the prototype for puts (), then it will not be :) those oil is oil - dio4
      • No, @ dio4, did not understand. const char * in the prototype, says that the functions don't care if the data is mutable or not (since it is not going to change them), but not because it ожидает указатель на неизменяемые данные - avp
      • I apologize, but you did not understand something here. Record of the form int puts (const char * s); says that funk. expects a pointer to char data, which it should treat as const data; those for it, these data are NOT changeable (and it doesn’t really care if you use your slang), because you cannot change it. So, an attempt to further change them in the code will cause an error at the compilation stage. That is what I had in mind. Well, who understood what everyone’s business is about. I suggest you be more correct in your assessments of other people. - dio4
      • And now carefully read the words from your answer - функция puts() ожидает указатель на неизменяемые данные (I’ll note separately - immutable data ). These words can be interpreted as - "you must transfer immutable data to a function" or even - "you cannot transfer changeable data to a function", which is fundamentally wrong. You can pass any data (in the sense of write protection) to the function with the const char * prototype, but you do not need to pass constants to the function with the char * prototype. I hope, now you understand what I meant by leaving my first comment. - avp

      At least in the GNU C preprocessor there is such a thing called stringification , which allows you to convert macro arguments to string constants.
      (which can already be passed to puts() ).

      You can write something like this:

       #include <stdio.h> #define A 33 #define S "33" #define xstr(s) str(s) #define str(s) #s int main (int ac, char *av[]) { puts("A name: " str(A)); // компилятор "склеивает" идущие подряд строковые константы puts("A value: " xstr(A)); puts("S name: " str(S)); puts("S value: " xstr(S)); return puts("End") == EOF; } 

      and to get

       avp@wubu:hashcode$ gcc tt.c && ./a.out A name: A A value: 33 S name: S S value: "33" End avp@wubu:hashcode$ 

      such a result.

      Note that for substitution of the value of the macro argument, their nesting is needed.

      • In studio 2015, this also works. - PinkTux