Scope
In the Basic Concepts section, the concept of scope was introduced. It is important to revisit the
distinction between local types and global types, and how to declare variables of each. To declare a
local variable, you place the declaration at the beginning (i.e. before any nondeclarative statements)
of the block the variable is intended to be local to. To declare a global variable, declare the variable
outside of any block. If a variable is global, it can be read, and written, from anywhere in your
program.
local variable, you place the declaration at the beginning (i.e. before any nondeclarative statements)
of the block the variable is intended to be local to. To declare a global variable, declare the variable
outside of any block. If a variable is global, it can be read, and written, from anywhere in your
program.
Global variables are not considered good programming practice, and should be avoided whenever
possible. They inhibit code readability, create naming conflicts, waste memory, and can create
difficulttotrace bugs. Excessive usage of globals is usually a sign of laziness and/or poor design.
However, if there is a situation where local variables may create more obtuse and unreadable code,
there's no shame in using globals. (Implementing malloc, which is a function discussed later, is one
example of something that is simply too much more difficult to write without at least one global
variable.)
possible. They inhibit code readability, create naming conflicts, waste memory, and can create
difficulttotrace bugs. Excessive usage of globals is usually a sign of laziness and/or poor design.
However, if there is a situation where local variables may create more obtuse and unreadable code,
there's no shame in using globals. (Implementing malloc, which is a function discussed later, is one
example of something that is simply too much more difficult to write without at least one global
variable.)
Other Modifiers
Included here, for completeness, are more of the modifiers that standard C provides. For the
beginning programmer, static and extern may be useful. volatile is more of interest to advanced programmers. register and auto are largely deprecated and are generally not of interest to either beginning or advanced programmers.
static is sometimes a useful keyword. It is a common misbelief that the only purpose is to make a variable stay in memory.
When you declare a function or global variable as static it will become internal. You cannot access
the function or variable through the extern (see below) keyword from other files in your project.
When you declare a local variable as static, it is created just like any other variable. However, when
the variable goes out of scope (i.e. the block it was local to is finished) the variable stays in memory,
retaining its value. The variable stays in memory until the program ends. While this behaviour
resembles that of global variables, static variables still obey scope rules and therefore cannot be
accessed outside of their scope.
the function or variable through the extern (see below) keyword from other files in your project.
When you declare a local variable as static, it is created just like any other variable. However, when
the variable goes out of scope (i.e. the block it was local to is finished) the variable stays in memory,
retaining its value. The variable stays in memory until the program ends. While this behaviour
resembles that of global variables, static variables still obey scope rules and therefore cannot be
accessed outside of their scope.
Variables declared static are initialized to zero (or for pointers, NULL) by default.
You can use static in (at least) two different ways. Consider this code, and imagine it is in a file called jfile.c:
static int j = 0;
void upj(void)
{
{
static int k = 0;
j++;
j++;
}
void downj(void)
{
{
j;
}
The j var is accessible by both upj and downj and retains its value. the k var also retains its value,
but is only accessible to upj. static vars are a good way to implement encapsulation, a term from the objectoriented way of thinking that effectively means not allowing changes to be made to a variable except through function calls.
extern is used when a file needs to access a variable in another file that it may not have
#included directly. Therefore, extern does not actually carve out space for a new variable, it just provides the compiler with sufficient information to access the remote variable.
volatile is a special type modifier which informs the compiler that the value of the variable may be changed by external entities other than the program itself. This is necessary for certain programs compiled with optimizations if a variable were not defined volatile then the compiler may assume that certain operations involving the variable are safe to optimize away when in fact they
aren't. volatile is particularly relevant when working with embedded systems (where a program may not have complete control of a variable) and multithreaded applications.
auto is a modifier which specifies an "automatic" variable that is automatically created when in
scope and destroyed when out of scope. If you think this sounds like pretty much what you've been
doing all along when you declare a variable, you're right: all declared items within a block are
implicitly "automatic". For this reason, the auto keyword is more like the answer to a trivia question
than a useful modifier, and there are lots of very competent programmers that are unaware of its
existence.
scope and destroyed when out of scope. If you think this sounds like pretty much what you've been
doing all along when you declare a variable, you're right: all declared items within a block are
implicitly "automatic". For this reason, the auto keyword is more like the answer to a trivia question
than a useful modifier, and there are lots of very competent programmers that are unaware of its
existence.
register is a hint to the compiler to attempt to optimize the storage of the given variable by
storing it in a register of the computer's CPU when the program is run. Most optimizing compilers do this anyway, so use of this keyword is often unnecessary. In fact, ANSI C states that a compiler can ignore this keyword if it so desires and many do. Microsoft Visual C++ is an example of an implementation that completely ignores the register keyword.
Concepts
•
oncept
• ariable
• ype
•
rray
In this section
•
variable
•
type
•
array
Simple Input and Output
When you take time to consider it, a computer would be pretty useless without some way to talk to the people who use it. Just like we need information in order to accomplish tasks, so do computers. And just as we supply information to others so that they can do tasks, so do computers.
These supplies and returns of information to a computer are called input and output. 'Input' is
information supplied to a computer or program. 'Output' is information provided by a computer or program. Frequently, computer programmers will lump the discussion in the more general term input/output or simply, I/O.
In C, there are many different ways for a program to communicate with the user. Amazingly, the
most simple methods usually taught to beginning programmers may also be the most powerful. In
the "Hello, World" example at the beginning of this text, we were introduced to a Standard Library
file stdio.h, and one of its functions, printf(). Here we discuss more of the functions that stdio.h
gives us.
most simple methods usually taught to beginning programmers may also be the most powerful. In
the "Hello, World" example at the beginning of this text, we were introduced to a Standard Library
file stdio.h, and one of its functions, printf(). Here we discuss more of the functions that stdio.h
gives us.
Output using printf()
Recall from the beginning of this text the demonstration program duplicated below:
#include <stdio.h>
int main(void)
{
{
printf("Hello, world!\n"); return 0;
}
If you compile and run this program, you will see the sentence below show up on your screen:
Hello, world!
This amazing accomplishment was achieved by using the function printf(). A function is like a "black box" that does something for you without exposing the internals inside. We can write
functions ourselves in C, but we will cover that later.
functions ourselves in C, but we will cover that later.
You have seen that to use printf() one puts text, surrounded by quotes, in between the brackets. We call the text surrounded by quotes a literal string (or just a string), and we call that string an
argument to printf.
argument to printf.
As a note of explanation, it is sometimes convenient to include the open and closing parentheses
after a function name to remind us that it is, indeed, a function. However usually when the name of the function we are talking about is understood, it is not necessary.
As you can see in the example above, using printf() can be as simple as typing in some text, surrounded by double quotes (note that these are double quotes and not two single quotes). So, for example, you can print any string by placing it as an argument to the printf() function:
printf("This sentence will print out exactly as you see it...");
And once it is contained in a proper main() function, it will show:
This sentence will print out exactly as you see it...
Printing numbers and escape sequences
Placeholder codes
The printf function is a powerful function, and is probably the mostused function in C programs.
For example, let us look at a problem. Say we don't know what 1905 + 31214 is. Let's use C to get the answer.
We start writing
#include <stdio.h> /* this is important, since printf
can't be used without this line */
int main(void)
{
printf("1905+31214 is"); return 0;
}
but here we are stuck! printf only prints strings! Thankfully, printf has methods for printing numbers. What we do is put a placeholder format code in the string. We write:
printf("1905+31214 is %d", 1905+31214);
The placeholder %d literally "holds the place" for the actual number that is the result of adding 1905
to 31214.
to 31214.
These placeholders are called format specifiers. Many other format specifiers work with printf. If we have a floatingpoint number, we can use %f to print out a floatingpoint number, decimal point and all. An incomplete list is:
•
•
•
•
•
•
•
•
•
%i int (same as %d) %f float
%lf double
%s string
%s string
%x hexadecimal
A more complete list is in the File I/O section.
Tabs and newlines
What if, we want to achieve some output that will look like:
1905
31214 +
printf will not put line breaks in at the end of each statement: we must do this ourselves. But
how?
how?
What we can do is use the newline escape character. An escape character is a special character that
we can write but will do something special onscreen, such as make a beep, write a tab, and so on.
we can write but will do something special onscreen, such as make a beep, write a tab, and so on.
To write a newline we write \n. All escape characters start with a backslash. So to achieve the output above, we write
printf(" 1905\n31214 +\n\n%d", 33119);
or to be a bit clearer, we can break this long printf statement over several lines. So our program will
be:
be:
#include <stdio.h>
int main(void)
{
{
printf(" 1905\n");
printf("31214 +\n");
printf("\n");
printf("%d", 33119);
return 0;
printf("\n");
printf("%d", 33119);
return 0;
}
There are other escape characters we can use. Another common one is to use \t to write a tab. You can use \a to ring the computer's bell, but you should not use this very much in your programs, as excessive use of sound is not very friendly to the user.
Other output methods
puts()
The puts() function is a very simple way to send a string to the screen when you have no
placeholders to be concerned about. It works very much like the printf() function we saw the "Hello, World!" example:
puts("Print this string.");
will print to the screen:
Print this string.
followed by the newline character (as discussed above). (The puts function appends a newline character to its output.) The fputs function is similar:
fputs("Print this string via fputs", stdout);
will print to the stdout file (usually the screen):
Print this string via fputs
without a newline tacked on to the end.
Since puts() and fputs() do not allow the placeholders and the associated formatting that printf()
allows, for most programmers learning printf() is sufficient for their needs.
Input using scanf()
The scanf() function is the input method equivalent to the printf() output function simple yet
powerful. In its simplest invocation, the scanf format string holds a single placeholder representing the type of value that will be entered by the user. These placeholders are exactly the same as the printf() function %d for ints, %f for floats, and %lf for doubles.
There is, however, one variation to scanf() as compared to printf(). The scanf() function requires the memory address of the variable to which you want to save the input value. While pointers are
possible here, this is a concept that won't be approached until later in the text. Instead, the simple
technique is to use the addressof operator, &. For now it may be best to consider this "magic"
before we discuss pointers.
possible here, this is a concept that won't be approached until later in the text. Instead, the simple
technique is to use the addressof operator, &. For now it may be best to consider this "magic"
before we discuss pointers.
A typical application might be like this:
#include <stdio.h>
int main(void)
{
{
int a;
printf("Please input an integer value: "); scanf("%d", &a);
}
If you are trying to input a string using scanf, you should not include the & operator.
If you were to describe the effect of the scanf() function call above, it might read as: "Read in an integer from the user and store it at the address of variable a ".
Note of caution on inputs: When data is typed at a keyboard, the information does not go straight to the program that is running. It is first stored in what is known as a buffer a small amount of memory reserved for the input source. Sometimes there will be data left in the buffer when the program wants to read from the input source, and the scanf() function will read this data instead of waiting for the user to type something. The function fflush(stdin) may fix this issue on some
computers and with some compilers, by clearing or "flushing" the input buffer. But this isn't
generally considered good practice and may not be portable if you take your code to a different computer with a different compiler, your code may not work properly.
computers and with some compilers, by clearing or "flushing" the input buffer. But this isn't
generally considered good practice and may not be portable if you take your code to a different computer with a different compiler, your code may not work properly.
Examples
Operators and Assignments
In C, simple math is very easy to handle. The following operators exist: + (addition), (subtraction), * (multiplication), / (division), and % (modulus); You likely know all of them from your math
classes except, perhaps, modulus. It returns the remainder of a division (e.g. 5 % 2 = 1).
classes except, perhaps, modulus. It returns the remainder of a division (e.g. 5 % 2 = 1).
Care must be taken with the modulus, because it's not the equivalent of the mathematical modulus:
(5) % 2 is not 1, but 1. Division of integers will return an integer, and the division of a negative
integer by a positive integer will round towards zero instead of rounding down (e.g. (5) / 3 = 1 instead of 2).
There is no inline operator to do the power (e.g. 5 ^ 2 is not 25, and 5 ** 2 is an error), but there is a
power function.
power function.
The mathematical order of operations does apply. For example (2 + 3) * 2 = 10 while 2 + 3 * 2 = 8.
The order of precedence in C is BFDMAS: Brackets, Functions, Division or Multiplication (from
left to right, whichever comes first), Addition or Subtraction (also from left to right, whichever
comes first).
The order of precedence in C is BFDMAS: Brackets, Functions, Division or Multiplication (from
left to right, whichever comes first), Addition or Subtraction (also from left to right, whichever
comes first).
Assignment in C is simple. You declare the type of variable, the name of the variable and what it's equal to. For example, int x = 0; double y = 0.0; char z = 'a';
#include <stdio.h>
int main()
{
int i = 0, j = 0;
while( (i < 5) && (j < 5) ) { /* while i is less than 5 AND j is less than 5, loop */
++j; /* prefix increment, increases by 1 immediately */
printf("i equals: %d\tj equals: %d\n", i, j); /* will print current variable values */
i++; /* postfix increment, increases by 1 next time the variable is
called, therefore i will be equal to 0 in the beginning */
}
called, therefore i will be equal to 0 in the beginning */
}
return 0;
}
}
will display the following:
i equals: 0 j equals: 1
i equals: 1 j equals: 2
i equals: 2 j equals: 3
i equals: 3 j equals: 4
i equals: 4 j equals: 5
The <math.h> header contains prototypes for several functions that deal with mathematics. In the 1990 version of the ISO standard, only the double versions of the functions were specified; the 1999 version added the float and long double versions.
The functions can be grouped into the following categories:
Trigonometric functions
The acos and asin functions
The acos functions return the arccosine of their arguments in radians, and the asin functions
return the arcsine of their arguments in radians. All functions expect the argument in the range [1
,+1]. The arccosine returns a value in the range [0,π]; the arcsine returns a value in the range [π
/2,+π/2].
,+1]. The arccosine returns a value in the range [0,π]; the arcsine returns a value in the range [π
/2,+π/2].
#include <math.h>
float asinf(float x); /* C99 */ float acosf(float x); /* C99 */ double asin(double x);
double acos(double x);
long double asinl(long double x); /* C99 */
long double acosl(long double x); /* C99 */
long double acosl(long double x); /* C99 */
The atan and atan2 functions
The atan functions return the arctangent of their arguments in radians, and the atan2 function return the arctangent of y/x in radians. The atan functions return a value in the range [π/2,+π/ (the reason why ±π/2 are included in the range is because the floatingpoint value may represen t infinity, and atan(±∞) = ±π/2); theatan2 functions return a value in the range [π,+π]. Foratan2, a domain error may occur if both arguments are zero.
#include <math.h>
float atanf(float x); /* C99 */
float atan2f(float y, float x); /* C99 */ double atan(double x);
double atan2(double y, double x);
long double atanl(long double x); /* C99 */
long double atan2l(long double y, long double x); /* C99 */
The cos, sin, and tan functions
The cos, sin, and tan functions return the cosine, sine, and tangent of the argument, expressed in
radians.
radians.
#include <math.h>
float cosf(float x); /* C99 */ float sinf(float x); /* C99 */ float tanf(float x); /* C99 */ double cos(double x);
double sin(double x);
double tan(double x);
double tan(double x);
long double cosl(long double x); /* C99 */
long double sinl(long double x); /* C99 */
long double tanl(long double x); /* C99 */
long double sinl(long double x); /* C99 */
long double tanl(long double x); /* C99 */
Hyperbolic functions
The cosh, sinh and tanh functions compute the hyperbolic cosine, the hyperbolic sine, and the hyperbolic tangent of the argument respectively. For the hyperbolic sine and cosine functions, a range error occurs if the magnitude of the argument is too large.
#include <math.h>
float coshf(float x); /* C99 */ float sinhf(float x); /* C99 */ float tanhf(float x); /* C99 */ double cosh(double x);
double sinh(double x);
double tanh(double x);
double tanh(double x);
long double coshl(long double x); /* C99 */
long double sinhl(long double x); /* C99 */
long double tanhl(long double x); /* C99 */
long double sinhl(long double x); /* C99 */
long double tanhl(long double x); /* C99 */
Exponential and logarithmic functions
The exp functions
The exp functions compute the exponential function of x (ex). A range error occurs if the magnitude of x is too large.
#include <math.h>
float expf(float x); /* C99 */ double exp(double x);
long double expl(long double x); /* C99 */
The frexp, ldexp, and modf functions
The frexp functions break a floatingpoint number into a normalized fraction and an integer power of 2. It stores the integer in the object pointed to by ex.
The frexp functions return the value x such that x has a magnitude of either [1/2, 1) or zero, and value equals x times 2 to the power *ex. If value is zero, both parts of the result are zero.
The ldexp functions multiply a floatingpoint number by a integral power of 2 and return the result. A range error may occur.
The modf function breaks the argument value into integer and fraction parts, each of which has the same sign as the argument. They store the integer part in the object pointed to by *iptr and return the fraction part.
#include <math.h>
float frexpf(float value, int *ex); /* C99 */ double frexp(double value, int *ex);
long double frexpl(long double value, int *ex); /* C99 */ float ldexpf(float x, int ex); /* C99 */
double ldexp(double x, int ex);
long double ldexpl(long double x, int ex); /* C99 */ float modff(float value, float *iptr); /* C99 */
double modf(double value, double *iptr);
double modf(double value, double *iptr);
long double modfl(long double value, long double *iptr); /* C99 */
The log and log10 functions
The log functions compute the natural logarithm of the argument and return the result. A domain error occurs if the argument is negative. A range error may occur if the argument is zero.
The log10 functions compute the common (base10) logarithm of the argument and return the
result. A domain error occurs if the argument is negative. A range error may occur if the argument
is zero.
is zero.
#include <math.h>
float logf(float x); /* C99 */ double log(double x);
long double logl(long double x); /* C99 */ float log10f(float x); /* C99 */
double log10(double x);
long double log10l(long double x); /* C99 */
Power functions
The pow functions
The pow functions compute x raised to the power y and return the result. A domain error occurs if x is negative and y is not an integral value. A domain error occurs if the result cannot be
represented when x is zero and y is less than or equal to zero. A range error may occur.
represented when x is zero and y is less than or equal to zero. A range error may occur.
#include <math.h>
float powf(float x, float y); /* C99 */ double pow(double x, double y);
long double powl(long double x, long double y); /* C99 */
The sqrt functions
The sqrt functions compute the nonnegative square root of x and return the result. A domain error occurs if the argument is negative.
#include <math.h>
float sqrtf(float x); /* C99 */ double sqrt(double x);
long double sqrtl(long double x); /* C99 */
Nearest integer, absolute value, and remainder functions
The ceil and floor functions
The ceil functions compute the smallest integral value not less than x and return the result; the floor functions compute the largest integral value not greater than x and return the result.
#include <math.h>
float ceilf(float x); /* C99 */ double ceil(double x);
long double ceill(long double x); /* C99 */ float floorf(float x); /* C99 */
double floor(double x);
long double floorl(long double x); /* C99 */
The fabs functions
The fabs functions compute the absolute value of a floatingpoint number x and return the result.
#include <math.h>
float fabsf(float x); /* C99 */ double fabs(double x);
long double fabsl(long double x); /* C99 */
The fmod functions
The fmod functions compute the floatingpoint remainder of x/y and return the value x i * y, for some integer i such that, if y is nonzero, the result has the same sign as x and magnitude less than
the magnitude of y. If y is zero, whether a domain error occurs or the fmod functions return zero is implementationdefined.
the magnitude of y. If y is zero, whether a domain error occurs or the fmod functions return zero is implementationdefined.
#include <math.h>
float fmodf(float x, float y); /* C99 */ double fmod(double x, double y);
long double fmodl(long double x, long double y); /* C99 */
0 comments:
Post a Comment