Logo  

CS351 - Computer Organization

Reading:

Data literals (constants)

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:

Type Example literal
* char 'A'
* int 100
* double 1.0
* char * or char[]
(a C string)
"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.

Integer literals

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.

Integer suffixes: Type Example
u or U unsigned 1U
l or L long 1L
ll or LL long long 1LL

Suffixes can be combined, i.e. 1ULunsigned 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.)

Floating point literals

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.)

Character literals (single quoted characters):

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.

* 'c-char' ASCII: ex: '0' → 48, 'A' → 65
u8'c-char' UTF-8 (C11)
L'c-char' Wide char (wchar_t)

where c-char is a basic character (i.e. one you can type on your keyboard) from the source, minus ', \ and newline.

Escape sequence
* \' single quote
* \" double quote
\? question mark
* \\ backslash
\a audible bell
\b backspace
\f form feed - new page
* \n line feed - new line (moves cursor to beginning of the next line)
* \r carriage return (moves cursor back to the beginning of the line)
* \t horizontal tab (moves cursor to next tab stop)
\v vertical tab
* \nnn arbitrary octal value (nnn, where n is an octal digit (0-7))
\xnn arbitrary hexadecimal value (n is 0-9 or a-f/A-F)
\unnnn universal character name (Unicode value); may result in several characters. Code point U+nnnn
\Unnnnnnnn universal character name (Unicode value); may result in several characters. Code point U+nnnnnnnn

* = Ones you should remember.

  • Singled quoted characters are just aliases for their ASCII numeric value, i.e. 'A' == 65, '\n' == 10, etc. You can see a listing of ASCII values by reading the man page for ascii (man ascii)

String literals

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"

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.

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.

Code comments:

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

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.

Examples:

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.

Assignment:

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.

var = value Assigns value to the variable 'var'. Data moves from right to left.
Value can be a complete expression itself.
⟵ data
a = 5; a is set to 5
a = b = 5; Internally same as: a = (b = 5);
b is set to 5, then a is set to 5.

Remember:

  • The "value" of an assignment is the value on the right side of the =.
  • The left side of an = must be a variable.
  • Whatever data was in the variable is completely replaced by the new value.

Expressions & operators:

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.

Mathematical operations:

Operator What it does:
* + Add: a + b
* - Subtract: a - b
* * Multiply: a * b
* / Divide: a / b
* % Modulus: a % b == integer remainder of a / b
* ++ Variable increment
* -- Variable decrement

* = Remember these operators

Pre-increment/decrement: ++a Increments the variable before using it's value:

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 = 5;
x = a++;
// Aftwards a will equal 6, but x equals 5 (a's value before incrementing)

same as:

a = 5;
x = a;
a = a + 1;

Input & Output:

Input and Output (I/O) to and from your terminal is controlled through three "streams":

Stream What it usually represents
* stdin Input (usually from the keyboard)
* stdout Normal output (usually to your terminal screen)
stderr High priority output (also usually to your screen)

* = Remember these I/O streams

The stdio.h header file

#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.

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:


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().

Printf() and Scanf()

printf():

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 , ... );

  • Common format codes for printf() (man 3 printf):
Format code
Integers
* %d Signed decimal (integer)
* %ld Long integer
%u Unsigned decimal (integer)
%o Unsigned octal
%x Unsigned hexadecimal (lowercase)
%X Unsigned hexadecimal (uppercase)
Floating point
* %f Float
* %lf Double (normal format)
%e Engineering format
Characters / strings
* %c single character
* %s String (null ('\0') terminated sequence of characters)
Misc
* %% Output a literal '%' character

* = Remember these

Example:

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.

Output Field width

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.

scanf():

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 , ... );

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):

Format code
Integers
* %d Signed decimal (integer)
* %ld Long integer
%u Unsigned decimal (integer)
%o Unsigned octal
%x Unsigned hexadecimal (upper or lowercase)
Floating point
* %f Float (any format)
* %lf Double (any format)
Characters / strings
* %c A single character
* %s A one word string
Misc
%% Matches a literal '%' character

* = Remember these.

Example:

int a, b;
// Prints a prompt before calling scanf()
printf("Enter two space separated integers: ");
scanf("%d %d", &a, &b);
        └──┼────┘   │
           └────────┘


which outputs:

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():

num1.c


#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.
}

num2.c


#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;
}