Literals or constants are (or can be) placed in read-only memory, and in the case of strings, usually cannot be modified at run time. A data literal will usually take the form of one of the basic C data-types:
char
'A'
int
100
double
1.0
char *
char[]
"abc"
* = Remember these types and examples.
Though 0, 0.0, '\0' and NULL all represent numeric zero, they use different amounts of storage and are interpreted by the computer in different ways and one should take some care that you're using the right form in the right place. For example attempting to put an integer literal into a char variable will cause the value to be truncated to fit inside the variable, potentially losing the original value.
0
0.0
'\0'
NULL
Numbers like 0 or 100, etc. with no decimal point are integer literals. Normally they are of size int (i.e. 32 bits), but can be made different sizes, which is usually only important when doing binary arithmetic.
u
U
unsigned
1U
l
L
long
1L
ll
LL
long long
1LL
Suffixes can be combined, i.e. 1UL → unsigned long.
1UL
unsigned long
Integer literals can also be represented in other numeric bases, such as hexadecimal (i.e. Base 16 numbers, ex: 0x00FA20EE), octal (i.e. Base 8 numbers, ex: 0644), and binary (i.e. Base 2 numbers, 0b110101011.)
0x00FA20EE
0644
0b110101011
Numbers that contain a decimal point or are in engineering notation (ex: 5e10) are always floating point values and are typically of size double. A float literal can be converted to a float using a f or F suffix (ex: 5.2f) or a long double using a l or L suffix (ex: 5.2L.)
5e10
f
F
5.2f
5.2L
Characters inside of a single quotes (') are character literals, they are converted to their ASCII value, so are actually numeric values. The prefixes u8 or L modify the character encoding to UTF-8 or Wide characters (essentially UTF-16.). For our purposes we only care about basic single quoted characters.
'
u8
'0'
u8'
L'
where c-char is a basic character (i.e. one you can type on your keyboard) from the source, minus ', \ and newline.
\
\'
\"
\?
\\
\a
\b
\f
\n
\r
\t
\v
0-7
\x
0-9
a-f
A-F
\u
\U
* = Ones you should remember.
'\n'
man ascii
Like character literals above, but strings of characters enclosed in double quotes: i.e. "..."
"
Two or more string literals placed side by side may be concatenated into a single string literal: "abc" "def" -> "abcdef"
"def"
"abcdef"
A null byte ("\0") is always appended to the end of a string literal, i.e. "abc" in memory is "abc\0" and so takes at least 4 bytes.
"\0"
"abc\0"
Examples:
"Hello, world!\n" ← Hello, world! followed by a newline character. "Col1\tCol2" ← two columns separated by a tab character. "He said \"Hi!\"." ← escaping double quotes inside of a string.
"Hello, world!\n"
Hello, world!
"Col1\tCol2"
"He said \"Hi!\"."
Comments in code help to describe what the code does, they should be used somewhat sparingly though, either to remind you or others the thinking processes involved or expected inputs and outputs for functions and the like.
Comments in C come in two different forms. Single line comments and multi-line comments. Single line comments start with two forward slashes (//) and continue until the end of the line. Multi-line comments start with a /* and continue until a ending */ is reached, and so can span multiple lines.
//
/*
*/
Note that multi-line comments cannot be nested (i.e. you cannot have a complete multi-line comment inside of another multi-line comment,) but can include single line comments inside of them.
Example:
/** * This is how I normally write out multi-line comments, all the *'s between * first /* until the ending */ is just decoration to make it look pretty. */
Variables are names given to locations in memory used to store data. Like a piece of paper onto which values may be written. However this is digital paper and when you write a new value onto the paper, the old value is erased and completely replaced with the new value.
Valid names for variables (sometimes called identifiers) can start with any upper or lower-case letter or the underscore (_) and can then be followed by any letter, number or underscore. Variables cannot start with a number for example, because it would confuse the compiler, which might think it was a number and not a variable. Variable naming is one of those rules of program grammar that you will need to remember.
Variables in C each have their own data-type, which is specified when declaring the variable. To declare a variable, first specify the type, followed by one or more variable names separated by commas.
int a; // Defines an integer called a unsigned int foo; // An unsigned integer called foo double a, b; // Two doubles, a and b char nl = '\n'; // A character called nl that is set to the newline character</div>
As seen in the example above, variables can be assigned a value when they are declared, using the assignment (=) operator, followed by a (usually) constant value.
=
NOTE: = is not the same as == (equality test).
==
To place data into a variable, it needs to be assigned to it, and to do this, we use the assignment operator in an expression. Data is read from the right side of the equal sign and written to the storage location on the left side. The left side of an assignment must be a variable.
a = 5;
a
a = b = 5;
a = (b = 5);
b
5
Remember:
Expressions are one of the primary means that work is done in a programming language. They usually deal with variables and/or function calls and resemble closely the kind of expressions that one sees in algebra, with the exception that the equal sign (assignment) is for setting the value of variables, rather than balancing both sides of an equation.
+
a + b
-
a - b
*
a * b
/
a / b
%
a % b
++
--
* = Remember these operators
Pre-increment/decrement: ++a Increments the variable before using it's value:
++a
a = 5; x = ++a; // Aftwards both a and x equal 6.
same as:
a = 5; a = a + 1; x = a;
Post-increment/decrement: a++ Increments the variable after using it's value:
a++
a = 5; x = a++; // Aftwards a will equal 6, but x equals 5 (a's value before incrementing)
a = 5; x = a; a = a + 1;
Input and Output (I/O) to and from your terminal is controlled through three "streams":
stdin
stdout
stderr
* = Remember these I/O streams
#include <stdio.h>
This is a header file, it provides 'prototypes' for many of the I/O functions a C program might use. If we use functions such as printf() or scanf() in our C programs, then we will need to include the stdio.h header file. You will almost always need to include this header file for your programs to work.
printf()
scanf()
stdio.h
What is a function prototype anyway? If you read the online man page for a function, such as say, for putchar (i.e. man 3 putchar) you will see something like:
putchar
man 3 putchar
PUTS(3) Linux Programmer's Manual PUTS(3) NAME fputc, fputs, putc, putchar, puts - output of characters and strings SYNOPSIS #include <stdio.h> int fputc(int c, FILE *stream); int fputs(const char *s, FILE *stream); int putc(int c, FILE *stream); int putchar(int c); int puts(const char *s); DESCRIPTION fputc() writes the character c, cast to an unsigned char, to stream. fputs() writes the string s to stream, without its terminating null byte ('\0'). putc() is equivalent to fputc() except that it may be implemented as a macro which evaluates stream more than once. putchar(c) is equivalent to putc(c, stdout). ...
Pay close attention to the SYNOPSIS, which lists among other things the header file you should include in order to use the function(s) and then the prototypes for each function. The prototype gives the return type and parameter data-types for each parameter so that you can see quickly at a glance the number of parameters and types for each that are required to use the function. The header files have the same prototypes for these functions to inform the compiler of the same information so that knows that the function exists and to verify that you are using the function correctly.
Looking at the above synopsis we can see that the putchar function requires an integer parameter (the character to be printed) and returns an integer result (which we learn in the 'RETURN VALUE' section is the value of the character written or EOF on error.) Now we have enough information to use putchar().
putchar()
One of the primary mechanisms of outputting text to the users screen is with the printf() function. Printf()'s first parameter must always be a string (a sequence of characters enclosed inside of double quotes ("), which may contain % format codes which will place the parameters that follow the format string (one at a time) at the location in the format string where the format code is located.
printf( format-string , ... );
printf(
,
);
%d
%ld
%u
%o
%x
%X
%f
%lf
%e
%c
%s
%%
* = Remember these
printf("Hello %s, your number is: %d.\n", "Steve", 10); └───────────────────┼─────────┘ │ └───────────────┘
which outputs:
Hello Steve, your number is: 10.
Note how the %s (the first % format code found in the format string) is replaced by the first parameter that follows the format string and the second format code (%d) is replaced by the second parameter that follows the format string.
You can control the output width of a number and left or right align the value by inserting numbers and an optional minus sign prefix between the % and the output and the format code. The first number specifies the number of character columns of the total output the number/string should be printed in. A number may overflow the field width if it is too large to fit.
Normally the output is right justified (i.e. aligned to the right,) prefixing a minus sign before the number left justifies the number.
A leading 0 on the number zero-pads the field (i.e. replaces the spaces with 0's)
Examples "%10d" Print a decimal value right aligned to 10 character columns "%08X" Prints a 8 digit uppercase hex value (leading zero padded) "%-30s" Prints a string left justified in a 30 column space.
"%10d"
"%08X"
"%-30s"
scanf() is the reverse of printf(), it gets formatted input from the terminal (keyboard). Like printf() it has a format string, which represents the format the input should be in (i.e. integers, floats, characters, strings, etc.).
scanf( fmt string , ... );
scanf(
Important things to remember about scanf():
Read input into variables. Integers and floats needs to have & (the address of operator) prefixed so that scanf can put data into them. & is unnecessary for arrays or pointers (which are already addresses.)
&
Return value is the number of items successfully read. ≤ 0 indicates failure. If you expect it to read 2 values, then you should make sure the return value is exactly 2, otherwise it is an error.
Common format codes for scanf() (man 3 printf):
* = Remember these.
int a, b; // Prints a prompt before calling scanf() printf("Enter two space separated integers: "); scanf("%d %d", &a, &b); └──┼────┘ │ └────────┘
Enter two space separated integers:
Then waits for input from the user. When the user enters two numbers with a space between them, the first number will be stored in the a variable, and the second in the b variable.
Note how each variable has a ampersand (&) prefixed before the variable name. The ampersand prefixed to a variable is the "address of" operator and is necessary for scanf() to let it know where in memory the a and b variables are located in memory so it can put the read values into them.
Some more complicated examples using scanf():
#include <stdio.h> int main(void) { float a; // A place to store the number while (scanf("%f", &a) == 1) { // Loop as long as we read a number printf("%f\n", a); // Print the number we read. } // We don't get to here until scanf() failed to read a number. return 0; // Returns from main, which exits the program. }
#include <stdio.h> int main(void) { double a, b; // A place to store the numbers while (scanf("%lf %lf", &a, &b) == 2) { // Loop as long as we read 2 numbers printf("%5.2f + %5.2f = %.3f", a, b, a+b); // Print the numbers we read. } // At this point scanf() failed to read exactly 2 numbers. return 0; }