2. One-dimensional arrays
An array stores a set of data of the same type.
Note indexing of elements always starts at zero,
so the first entry is a[0] not a[1].
It is sometimes useful to define the size of an array as a symbolic constant:
#define NPOINTS 100
int a[NPOINTS];
The array is then typically processed with a for loop:
for (i = 0; i < NPOINTS; ++i)
sum += a[i];
Changes in size are then taken care of all in one place.
Declaration: int a[size]; /* space for a[0].... a[size-1]
allocated. */
Usage: b=a[expr]; /* expr = integral expression
between 0 and size-1 */
3. One-dimensional arrays
• The index i is referred to as a subscript. Arrays can be initialized:
float a[5] = { 0.0, 1.0, 2.0, 3.0, 4.0 };
If some but not all elements are initialized, others are set to zero.
External and static arrays are initialized to zero by default anyway;
automatic arrays are not, although some compilers do so.
• Arrays can be declared without size! size is set to the number of
initializers:
float f[] = {0.0, 1.0, 2.0, 3.0, 4.0};
is equivalent to the above.
• For character arrays an alternative is available:
char s[] = “abc”;
is equivalent to
char s[] = {‘a’, ‘b’, ‘c’, ‘0’};
The 0 at the end here is the “end-of-character-string” symbol.
4. One-dimensional arrays
pointers
A common error is to access elements beyond the end of the array;
e.g. a[N] in an N-element array.
Ensure that subscripts stay within bounds
(Remember array subscript starts at zero!).
float a[5] = {0.0}, b=555.5;
printf(“%fn“,a[5]);
Example:
Wrong, but compiler may not complain!
What do you get for a[5]?
How is a stored in memory?
5. top of stack
bottom of stack
Address space of a program
text Code Write protected
(segmentation violation!)
0x0000
0xFFFF
Local variables
Function arguments
Return addresses of functions
Typically ~10kB
heap Dynamically allocated variables
top of heap
main
func1
func2
Stack frames:
stack
up close
stack
Global and static variables
bss
Constants (initialized data)
data
6. Addresses in memory – the & operator
int main(void)
{
int a=2, b=5;
....
}
b
2
5
a
...
... 4 bytes
of memory
Stack region of memory for a simple program
programmer‘s
view
fa44
fa40
fa5c
fa48
computer‘s
view ?
How to get address of a in memory?
&a would return the hex number fa48 in the example
Which variable to assign an address to?
pointers
7. Pointers
• variables are stored in particular locations, or addresses, in memory
• if v is a variable then &v is the address in memory of its stored value
• pointers are used to access these memory locations directly
Declaration: int *p;
declares that p is a pointer to the address of an int type variable.
If a is an integer, for example, we can then set p = &a;
If p holds the address of a variable, the indirection or dereferencing
operator * gives the value that is held at that address.
think of * as the inverse of &
don’t confuse it with the * used in the int *p declaration
think of int* as the type of p
*p is equivalent to a
8. Pointer example
int a=2, b=5, *p;
fa48
fa44
fa40
b
2
5
a
? p
2
5
fa48
p = &a; b = *p;
now p points
to variable a
2
2
fa48
b is set to a
p = &b;
2
2
fa44
now p points
to variable b
*p = 8; *(p+1)=3; *p=(int)p; p=(int*)&p;
3
8
fa44
pointer
arithmetic
3
fa44
fa44
typecast
to int
3
fa44
fa40
typecast
to pointer
2
8
fa44
fa48
fa44
fa40
pointer
assignment
9. Pointers
Exercise:
int i = 3, j = 5, *p = &i, *q = &j, *r;
double x;
Give values for:
*p
**&q
j* *p
j + *&i
j/ *p
* and & are unary operator (check your table for precedence)
Notice the use of a space between / and * to avoid j/*q,
which would have looked like the start of a comment...
do not point at constants (&3), expressions or register variables
10. Pointer to void
void * is a generic pointer, and can be assigned to any variable type.
However, for good practice you should always “type cast” it into the
appropriate pointer type.
This makes sure that the pointer types agree
p = (int *) v;
If v happens to point to some integer, this is the proper assignement:
Pointer must always have a type that they point to. Exception:
int *p;
void *v;
Example:
11. Call-by-reference
stack after
two nested
function calls
main
func1
func2
0xFFFF
a
0x0000
int func1(void)
{
int a;
func2(&a);
}
int func2(int *p)
{
....
}
func2 could change a in func1, if it had a pointer to it!
pass the pointer &a as a function argument!
(which itself would of course not be changed)
In C, only copies of variables are passed down to functions as values
How to use a function to change variables in the calling function?
p
12. Call-by-reference
#include <stdio.h>
void swap(int *, int *);
/*----------------------------------*/
int main(void)
{
int i = 3, j = 5;
swap (&i, &j);
printf(“%d %dn”, i, j); /* 5 3 is printed */
return 0;
}
/*----------------------------------*/
void swap(int *p, int *q)
{
int tmp;
tmp = *p;
*p = *q;
*q = tmp;
}
• Declare a function parameter to be a pointer
• Pass an address as an argument when the function is called
• Use the dereferenced pointer in the function body
function parameters are pointers to int
Pass the addresses of the variables
when calling the function
Inside the function, use the
dereference operator * to access the
values stored at the addresses you
sent down
Exercise: Change this program and make it rotate three variables: i → j, j
→ k and k → i.
13. Arrays and Pointers
If a is an array, i is an int, and p is a pointer,
a[i] is equivalent to *(a + i);
p[i] is equivalent to *(p + i);
if a is an array of int and p an integer pointer,
p = &a[0]; can be used to point to the first element,
p = &a[1]; to point to the second etc
The address operator can also be applied to array elements
But there‘s a better way!
In C, an array name is an address (or pointer) to the start of the array!
p = a; is equivalent to p = &a[0];
p = a+1; is equivalent to p = &a[1];
a is fixed, so that a = p; is illegal!
pointer arithemtic
14. Pointer arithmetic
If p and q are both pointing to elements of an array, p - q yields the
int value representing the number of array elements between p and q.
One of the powerful features of C!
If p is a pointer to a particular type, then p+1 yields the correct machine
address of the next variable of that type.
• If p is a pointer to int, then p+1 will point to address ff38
• If p is a pointer to char, then p+1 will point to address ff35
• if p is a pointer to double, then p+1 would point to address ff42
p points to address ff34
Example:
double a[2], *p, *q
p = a; /* points to base of array */
q = p + 1; /* equiv. q = &a[1] */
printf(“%dn”, q - p); /* 1 is printed */
printf(“%dn”, (int)q - (int)p); /* 8 is printed */
Example:
15. Example: summing an array
for (p = a; p < &a[N]; ++p)
sum += *p;
for (i = 0; i < N; ++i)
sum += *(a + i);
for (p = a, i = 0; i < N; ++i)
sum += p[i];
The following are examples for summing an array a,
with p being a pointer of the proper type of the array
Note however that because a is a constant pointer, expressions such as
a = p; ++a; a += 2 &a;
are illegal. We cannot change the value of a in the way that we can for p.
16. Exercise: Bubble sort
This is an extremely inefficient sorting algorithm!
Compile and run a program containing this function; then go through the
code, adding comments to ensure that you understand how it works.
(Then forget you ever knew it, and work with a better algorithm instead).
void swap(int *, int *); /* same swap function as before
*/
void bubble(int a[], int n) /* n is size of a */
{
int i,j;
for (i = 0; i < n-1; ++i)
for (j = n - 1; j > i; --j)
if (a[j-1] > a[j])
swap(&a[j-1],&a[j]);
}
Note that the swap function call could also have been written
swap(a + j - 1, a + j);
17. heap
Dynamic Memory Allocation
sizeof(int) finds the right
element size
calloc returns a pointer to void (i.e. pointer of no particular type) that
points to the start of the assigned space (or to NULL if there is not enough
space on the heap). You should cast the pointer to the proper type!
It is not always known in advance how big an array will
be in running a program. Two ways around this:
text
stack
bss
data
a = (int *) calloc(n,sizeof(int));
1. Set aside huge amounts of memory when writing
the program, and hope that it‘s more than needed
2. Take the memory that is needed “on the fly” from
the „heap“
The latter is obviously more intelligent and flexible.
If you need memory to store n array elements, each
of which is (say) an integer, you do this:
calloc stands for “contiguous allocation”
of memory: grab the memory in one lump
18. Dynamic Memory Allocation
If a is NULL, free has no effect; if it is the base address of the space
allocated by calloc( ) or malloc( ), the space is deallocated; ortherwise
there is a system-dependent error. If you don’t give the memory back,
but keep on taking more, you will eat it all until the program crashes.
a = (int *) calloc(n, sizeof(int));
int can be replaced with any other type
There is also an alternative:
where total_size = n * element_size.
a = (int *) malloc(total_size);
space allocated by calloc or malloc must be given back explicitly
by
free(a) /* where a is the pointer name */
before exiting the function.
initializes the
space with 0
no initialization
19. Example 1
a = malloc(n*sizeof(int));
/* allocates space for array a */
fill_array(a,n); /* fill with random nos 1-10 */
wrt_array(a,n); /* writes out the array */
printf("sum = %dnn", sum_array(a,n));
free(a);
Try it and see!
Notes about this code:
• srand(time(NULL)) “seeds” the random-number generator;
• rand() %19 takes the remainder when a random number is divided by
19, to give a random number between 0 and 18, so rand() %19 – 9
gives a random number between –9 and 9)
20. Example 2
-3 4 7 13 1 2 16
-3 1 2 4 7 13 16
/* Merge a[] of size m and b[] of size n into c[]; from K&P */
#include "mergesort.h“
void merge(int a[], int b[], int c[], int m, int n){
int i = 0, j = 0, k = 0;
while (i < m && j < n) c[k++]=((a[i] < b[j])? a[i++]:b[j++]);
while (i < m) c[k++] = a[i++]; /* pick up any remainder */
while (j < n) c[k++] = b[j++];
}
This is the basis for a standard sorting routine, called mergesort.
We’ll be looking at it in the problem sheet and in the weeks to come.
21. Pointer basics 1
Pointers contain memory locations
declaration: int *p;
declares that p is a pointer to the
address of an int type variable
dereferencing operator *
int a=2, b=5, *p;
fa48
fa44
fa40
b
a
p
2
5
fa48
How to access the object that p points to?????
*p returns the object
that p is pointing to
in the example,
*p is an integer number
Example:
22. Pointer basics 2
How to assign an address to p?????
p now points to a
p = &a;
If the object to be
addressed is already
declared, use the
& operator
If the object to be addressed is not declared,
use memory allocation
p = (int *) malloc(sizeof(int));
free(p) to return memory
p now points to the chunk of memory allocated
Object can be
accessed by
a or *p
Object can only be accessed by *p
because it hasn‘t got a name assigned
Memory returned when
a goes out of scope, for
example when function
returns
23. Arrays and pointers
Declaration: int b[N]; /* space for b[0].... b[N-1]
allocated. */
Usage:
p = (int *) calloc(N, sizeof(int));
p = (int *) malloc(N * sizeof(int));
Pointer arithmetic: p+1
Pointer to array: int *p; p = b;
element_i=b[i]; element_i=p[i];
element_i=*(p + i);
element_i=*(b + i);
array name b is a constant pointer to first array element
points to next array element
Declaration of array with memory allocation:
p is a variable pointer to first array element
int *p;
b = p; is illegal because
b is constant
p is now equivalent to b!
24. Strings
char astring[] = {'t','h','i','s',' ','i','s',' ',
't','e','d','i','o','u','s',
'n','0'};
In C strings are implemented as 1 dimensional arrays.
The type of the array elements is char
char bstring[] = “this is much better“;
In this case, no explicit 0 is needed (it is added automatically)
The last element must be the null character 0
This terminates the string, so the end of the string can be found
“abc” is a character array of size 4
•“a” is a two-element string, whereas
•‘a’ is a character.
25. Strings as pointers
Note the difference between arrays and pointer
• char *p = “abcde”;
here, the compiler puts the string constant abcde0 somewhere in memory,
then allocates a pointer that points to its first element.
• char s[] = “abcde”;
here, s is stored in 6 contiguous bytes along with the other variables of the
function. You can’t make “s” point anywhere else than to the start of the string.
The difference between the two ways of declaring strings
is explained in the next two slides!
As with other arrays, strings are treated as pointers:
char *p = “abc”;
printf(“%s %sn”, p, p+1); /* abc bc is printed */
Before scanning to an address, make sure sufficient memory is allocated
char *p = (char*) malloc(21); /* allocate memory to hold string */
scanf(“ %20s”, p); /* reads 20 characters from input */
no & character when pointers are used
26. String literals
Expressions like “abcd“ are called string literals.
When you include a string literal in
your program, two things happen:
The array elements a b c d 0
are placed somewhere in the data
segment of address space (close
to the code, at low addresses).
top of stack
text
0x0000
0xFFFF
heap
top of heap
stack
bss
d
0
c
b
a
data
this address
is returned
The address of a is returned.
If you want to reuse the string,
you must store the address in a
pointer variable.
(otherwise you will never find it again)
1.
2.
char *p; p = “abcd“;
p
27. Array of char
top of stack
text
0x0000
0xFFFF
heap
top of heap
bss
data
fixed address
pointed to by s
d
0
c
b
a
stack
char s[] = “abcd“;
This is how an array of char is initialized
Space is created on the stack for
5 characters.
1.
Constant pointer s created
on the stack. The address
it points to can never change!
2.
s
a b c d 0 are put at the proper
addresses s, s+1, s+2, ....
on the stack
3.
s = “abcd“; is illegal, because it attempts to change s
into the address of the string literal
28. /* Count the number of words in a string (from K & P) */
#include <ctype.h>
int word_cnt(const char *s)
{
int cnt = 0;
while (*s != ‘0’) { /* repeat until end of string */
while (isspace(*s)) /* skip white space */
++s;
if (*s != ‘0’) { /* must have found a word. */
++cnt; /* count it, then ignore all the */
/* rest of the characters in it */
while (!isspace(*s) && *s != ‘0’)
++s; /* skip the word */
}
}
return cnt;
}
Example: Word count
Points to start of array of chars, i.e. a string
Keep going as long as not pointing to end-
of-string char
If char is space, just move s on to next char
Not a space or end-of-string, so have found
a word... increment the word counter
Move on without counting until
we find the next space
29. String-handling functions
• char *strcat(char *s1, const char *s2)
takes two strings and concatenates (joins) them, putting result in s1.
Programmer must ensure s1 points to adequate space. A pointer to the
string s1 is returned.
• int strcmp(const char *s1, const char *s2)
Returns an integer that is <, equal or > 0 depending on whether s1 is
lexicographically (i.e. alphabetically) less than, equal to or greater than s2.
• char *strcpy(char *s1, const char *s2)
characters in s2 are copied into s1 until 0 is moved. Pointer s1 is returned.
• size_t strlen(const char *s)
returns count of number of characters before 0. (size_t is an integral
unsigned type; usually unsigned int.)
Various string-handling functions are available in the standard library,
if you
#include <string.h>
30. Implementation of string functions
char *strcat(char *s1, register const char *s2)
{
register char *p = s1;
while (*p)
++p;
while (*p++ = *s2++);
return s1;
}
char *strcpy(char *s1, register const char *s2)
{
register char *p = s1;
while (*p++ = *s2++);
return s1;
}
size_t strlen(const char *s)
{
size_t n;
for (n = 0; *s != '0'; ++s)
++n;
return n;
}
strcat
strcpy
strlen
return pointer
to char
register for
fast execution
iterate until end-of-string
character ‘0‘ is reached
31. Assignment of strings
char *p;
/* Dynamically allocate space */
p = (char*) malloc(37);
P = “text with no more than 36 characters“;
/* Declare array */
char s[37];
strcpy( s, “text with no more than 36 characters“);
If you don‘t want to assign text to an array of char or to
a dereferenced pointer during initialization, here‘s how to
do it later in the program:
For a string represented by a variable pointer:
For a string represented by an array name:
32. char str1[ ] = “1 2 3 go”, str2[100], tmp[100];
int a, b, c;
sscanf(str1, “%d%d%d%s”, &a, &b, &c, tmp);
sprintf(str2, “%s %s %d %d %dn”, tmp, tmp,
a, b, c);
printf(“%s”, str2);
Writing to strings: sprintf, sscanf
Read from str1 instead of from keyboard
• sprintf() writes to its first argument, which should be a pointer to char (string).
• sscanf() reads from its first argument instead of from the keyboard.
The functions sprintf()and sscanf()are string versions of the
functions printf()and sscanf(), respectively: they write to and from
strings instead of to and from the screen/keyboard.
Here, sscanf( ) takes input from str1; it reads 3 decimals and a string, putting
them into a, b, c and tmp respectively. Then sprintf( ) writes to str2; or, rather, it
writes characters in memory, beginning at the address str2.
Note that str2 already has adequate memory allocated (100 bytes) to write the whole
of the string – if this weren’t the case there would be an access violation (and crash).
Its output is two strings and three integers. Using printf() to print str2 to the
screen, we see that the output is go go 1 2 3
Note that if we use sscanf() to read from the string again, it starts from the
beginning, not from where it left off.
Read 3 numbers and a
string; put them in the
addresses of a, b, c and
tmp
34. One-dimensional arrays
...
a[1]
a[9]
a[0]
ff64
ff60
ff84
Computer memory is linearly addressed
int a[10];
ideal for representing 1-dimensonal arrays
a
What about 2-dimensional arrays?
a00 a01 a02 a03
a10 a11 a12 a13
a20 a21 a22 a23
a9
...
a1
a0
specify address for first element
a=a[0] and get others by offset
int *p=a;
What is the type of a?
a is pointer to int
35. for(i=0;i<3;i++) {
for(j=0;j<4;j++) {
a[i][j]=i*10+j;
printf(" %02d",
a[i][j]);
}
printf("n");
}
Two-dimensional arrays in address space
a23
a22
a21
a20
a13
a12
a11
a10
a03
a02
a01
a00
a00 a01 a02 a03
a10 a11 a12 a13
a20 a21 a22 a23
int a[3][4];
declaration:
a[i][j]
usage: int *b = (int*) a;
a[i][j] = *(b+4*i+j);
Base address:
int *b = &a[0][0];
int a[3][4];
b
b+1
b+2
b+3
b+4
a
a+1
a+2
int (*p)[4]=a;
What is the type of a?
a is a pointer to a1D-
array of 4 elements
36. Two-dimensional arrays
int a[3][4];
Array elements are stored contiguously, one after the other.
Alternative interpretation: three arrays of four arrays of int.
a[i][j]
*(a[i] + j)
(*(a + i))[j]
*((*(a + i)) + j)
*(&a[0][0] + 4*i + j)
Different ways to access element i,j:
3 rows and 4 columns
The array name a by itself is equivalent to &a[0]; it is a pointer to an
array with 4 elements. The base address of the array is &a[0][0].
The mapping between pointer values and array indices is called the
storage mapping function.
The compiler needs to know sizes in advance, because it needs to
know that a new row starts every n elements.
37. Multi-dimensional arrays
Initialization: Example for a 3D array:
int a[2][2][3] = {{{1,1,0},{2,0,0}}, {{3,0,0},{4,4,0}} };
From here the compiler can work out that the first size is 2. It is possible to
initialize all array elements to zero:
int a[2][2][3] = {0};
a[i][j]
a[i]
a
int a[M][N];
c[i][j][k]
c[i][j]
c[i]
c
int c[L][M][N];
x[i]
x
int x[N];
array element
pointer to element
pointer to array of
N elements
pointer to array of
N*M elements
declaration
38. Example: Adding array elements
int sum (int a[7] [9] [2]) /* 7x9x2 matrix */
{
int i, j, k, sum = 0;
for (i = 0; i < 7; ++i)
for (j = 0; j < 9; ++j)
for (k = 0; k < 2; ++k)
sum += a[i][j][k];
return sum;
}
Exercise 3:
write a short program in which you initialise a 3x3 matrix (with
numbers 1-9, for example), and then call functions that
(a) multiply
(b) add
all of the elements together, and print out the answer.
39. Passing arrays to functions
int sumarray(int a[][4]){
int i, j, sum = 0;
for (i=0; i<3; i++)
for (j=0; j<4; j++)
sum += a[i][j];
return sum;
}
int a[3][4], result;
...
result = sumarray(a);
Only the address of the first element is passed to the function
For the correct calculation of addresses, the array size must be
specified for every dimension except the first one
int sumarray(int *a,int n, int m){
int i, j, sum = 0;
for (i=0; i<n; i++)
for (j=0; j<m; j++)
sum += *(a + m*i + j)
return sum;
}
int a[3][4], result;
...
result =
sumarray(a[0],3,4);
This can be avoided only by passing a pointer to the first element
and calculating the adresses yourself:
40. typedef
Use the typedef command to define new data types in terms of old ones:
typedef int * pointer_to_int;
known type new type
Example:
typedef double scalar;
typedef scalar vector [3];
typedef scalar matrix [3] [3];
typedef vector matrix [3];
or equivalently:
scalar dot_product(vector x, vector y)
{
int i;
scalar sum = 0.0;
for (i = 0; i < N; ++i)
sum += x[i] * y[i];
return sum;
}
Application:
41. Arrays of pointers
w[6]
w[4]
w[2]
pp
w[5]
w[3]
w[1]
w[0]
w and
pp are
pointer
to pointer
w[i] and
*PP is
pointer
to int
*w[i]
and
**pp
is int
Arrays can be of any type,
including pointers int *w[N];
int **pp=w;
Example:
declaration
Arrays of pointers are more
flexible and faster to move
around than arrays of data.
More efficient use of memory
Applications:
• Alphabetical sorting of words
• Memory management by
operating system
No need to allocate memory in
advance
42. Ragged arrays
A group of words may be stored as
• a two-dimensional array of type char, or
• a one-dimensional array of pointers to char.
#include <stdio.h>
int main(void)
{
char a[2][9] = {"abc:", "an apple"};
char *p[2] = {"abc:", "an apple"};
printf("%c%c%c %s %sn", a[0][0], a[0][1], a[0][2], a[0], a[1]);
printf("%c%c%c %s %sn", p[0][0], p[0][1], p[0][2], p[0], p[1]);
return 0;
}
Example:
43. Ragged arrays
char a[2][9] = {"abc:",
"an apple"};
a is a 2D array, and its declaration
causes space for 2x9 = 18 chars to be
allocated. Only the first five elements
‘a’, ‘b’, ‘c’, ‘:’ and ‘0’ are used in a[0];
the rest are initialized to zero.
char *p[2] = {"abc:",
"an apple"};
p is a 1D array of pointers to char.
When it is declared, space for two
pointers is allocated. p[0] is initialized
to point at “abc:”, a string requiring
space for 5 chars. p[1] is initialized to
point at “an apple“ which requires
space for 9 chars. Thus, p does its
work in less space than a; it is also
faster, as no mapping function is
generated.
a b c : 0
a n a p p l e 0 a n a p p l e 0
a b c : 0
An array of pointers whose elements point to arrays
of different sizes is called a ragged array.
Note that a[0][8] is a
valid expression,
but p[0][8] is not.
44. Dynamic allocation of arrays
Explicitly declared multidimensional arrays have some drawbacks:
• Size of the array must be specified in advance
in the declaration
int a[3][3];
• Functions work only for arrays of a fixed size:
function(int a[][3])
Use array of pointers + memory allocation instead
To get an arbitrary size array of pointers, we dynamically allocate it,
creating a pointer to an array of pointers, each pointing at a 1D array.
This is not suitable for working with matrices of arbitrary size
45. Dynamic allocation of arrays
int i, j, n; /*i, j matrix indices; n size*/
double **a;
a = (double **) calloc(n, sizeof(double *));
for (i = 0; i < n; ++i)
a[i] = (double *) calloc(n, sizeof(double));
Allocate space for n elements
of size “pointer to double“
Allocate space for the matrix rows
(n elements of double), one at a time
a[1]
...
a[0]
a[n-1]
n
-
1
3
1 2
0
n
-
1
3
1 2
0
n
-
1
3
1 2
0
a
... matrix isn‘t necessarily
stored in a contiguous
block in memory!
46. Dynamic allocation of arrays
Matrix elements are accessed as usual:
a[i][j] is matrix element (double)
a[i] is pointer to double
Warning: no mapping between pointer values and array indices!
(&a[0][0]+i*n+j)
Memory must be properly returned (in the right order):
int i;
for (i = 0; i < n; ++i)
free(a[i]);
free(a);
function( double **a, n);
function(a,n);
Function calls without a priory knowledge of size:
For 3D arrays of arbitrary size, use pointer-to-pointer-to-pointer-to-double:
double ***a;
47. Mathematical functions
• There are no built-in mathematical functions in C
• Functions such as
sqrt() exp() log() sin() cos() tan()
are built into the mathematics library.
• All of these take one arguments of type double, and return a
value of type double;
• pow() takes two arguments, base and exponent, of type double
and returns as double.
• In order to use functions from the standard maths library, you
should #include <math.h> at the top of the program, and you
have to have -lm as an argument in your compilation command:
exponent
base