Lecture 5 - Conditionals & Functions

Download Report

Transcript Lecture 5 - Conditionals & Functions

C - Memory
•
•
•
•
•
•
Simple Types
Arrays
Pointers
Pointer to Pointer
Multi-dimensional Arrays
Dynamic Memory Allocation
1
Memory and Pointers
159.234
SIMPLE TYPES
When we create a variable in a program, we use the name of the
variable to access its value.
The computer only knows about memory locations (addresses) and
contents (values).
The compiler translates our instructions into something meaningful to
the computer,
int i, j;
allocates storage for two integers (sizeof(int), 4 bytes) and remembers
their addresses
i may be at address 100 and j at 104.
i = j;
is translated by the compiler into: copy 4 bytes at location 104 to
2
location 100
C-Memory
159.234
SIMPLE TYPES
When we include a numeric or character constant in a
program:
i = 6;
the compiler places the value '6' into the machine instruction.
If we also have
j = 6;
there will be two '6' s in our executable file.
3
C-Memory
159.234
ARRAYS
When we create an array, the compiler allocates as much
memory as requested and remembers the address of the first
element.
char s[80];
allocates 80 bytes starting at 108*.
*that is, continuing with our previous example
4
C-Memory
159.234
Array name
The name 's' is different from 'i‘
'i' refers to the value stored at address 100
's' refers to the address 108
We are not allowed to say:
s = 'a';
To access the value stored at s:
s[0] = 'a';
or
(*s) = 'a';
s is an address. The indirection operator * accesses the
contents stored at the address.
5
C-Memory
159.234
ARRAYS
s[i] is a shorthand way of writing *(s+i)
Adding
addresses
We can add an integer to an address – the result is an address.
(The integer is first multiplied by the size of the element being
pointed to)
Subtracting
addresses
The result of subtracting two addresses is an integer. The number
of elements.
Multiplying
addresses
We cannot multiply an address with an integer.
6
C-Memory
159.234
ARRAY CONSTANTS
A string cannot be 'part of an instruction'.
Instructions are fixed length – 4 or 8 bytes.
The compiler allocates memory for the string and remembers its
location.
strcpy(s,"Napoleon");
"Napoleon" is stored in memory at address 188
9 bytes are allocated (8 plus a NULL).
The text "Napoleon" is stored in the executable file and is placed at
location 188 when the program starts.
7
C-Memory
159.234
ARRAY CONSTANTS
If the constant appears twice in the program:
strcpy(s,"Napoleon");
strcpy(t,"Napoleon");
the compiler has the choice of creating two separate
memory areas each with the word "Napoleon", or using the
same area for both.
To save space it will normally do the latter.
8
C-Memory
159.234
Size of ARRAYS
Do we need to say how big arrays are? - Yes, otherwise the
compiler does not know how many bytes to allocate.
What about when we initialise strings?
char s[] = "Napoleon";
We don't need to give the size of the string – but the compiler
works it out itself.
See AddressArray.cpp
9
C-Memory
159.234
2-D ARRAYS
What about 2 dimensional arrays?
The compiler fools us a little – there is no such thing as a 2D array.
Only 1D arrays.
char array[20][80];
allocates 1600 bytes of memory. 'array' is the address of the first
byte.
array[3][5]
is converted by the compiler to:
*(array + 3*80 + 5)
similarly for 3 and 4 dimensional arrays.
See AddressArray.cpp
10
C-Memory
159.234
Specifying the array dimension at run-time
Can we specify the dimension at run-time?
- Not unless we use pointers.
A pointer is a variable that contains an
address.
char *p;
Now we have two addresses!
p is a variable, its value is an address. This
is the address we normally want.
The & operator gets the address of a
variable.
char *p;
char c;
p = &c;
p is at location 100
c is at location 104
the contents of p is 104.
The indirection operator * accesses the
contents of an address
p is somewhere in memory so it has an
address associated with its own position.
11
C-Memory
159.234
Using the subscripting operator with
pointers
(*p) = ‘N';
pointers and arrays look very similar! We can use the [ ] operator
with pointers
p[0] = ‘N';
Subscript operator
p points to a single character, so we can only access the 0'th
element.
Writing to p[1] causes the program to fail.
If we allocate memory from the heap, p can point to as many bytes
as we want:
12
void *malloc(size_t size);
C-Memory
159.234
malloc
p = (char *)malloc(80*sizeof(char));
allocates 80 bytes. p contains the address of the first character.
malloc can have a variable as an argument, so the size of the 'string' p can be set at
runtime.
char *p;
int i;
printf("How big is the string:");
scanf("%d", &i );
p = (char *)malloc(i*sizeof(char));
13
void *malloc(size_t size);
C-Memory
159.234
Declaring an ARRAY vs. Declaring a Pointer
char s[80];
char *p;
p = (char *)malloc(80*sizeof(char));
p and s behave very much the same.
p[12] = 'a';
s[12] = 'b';
strcpy(p,"Napoleon");
strcpy(s,"Napoleon");
printf("%s",p);
printf("%s",s);
There is a difference:
char s[80];
char *p;
char c;
p = &c; this is certainly ok
s = &c; this is NOT
s is not variable. Its value cannot change.
14
C-Memory
159.234
ARRAYS
Be very careful when 'initialising' a pointer
char *p = "Napoleon";
If "Napoleon" is a constant, used in many places
in the program then
p[0] = 'X';
Will change all “Napoleon"s into "Xapoleon".
15
C-Memory
159.234
2D arrays on the heap?
Several possibilities, but the syntax becomes
very difficult.
char (*p)[80];
p = (char (*)[80])malloc(10*80*sizeof(char));
p[0][0] = 'a';
is correct (and the round brackets are
required!)
typedef char string[80];
string *q;
char (*p)[80]; //pointer to a char
array
char *(p[80]); //array of pointers to
char
only the very brave or foolish use
these.
q = (string *)malloc(10*sizeof(string));
is equivalent and looks better, although the
typedef is a bit strange.
16
C-Memory
159.234
POINTER TO A POINTER
A third method is more common and uses a pointer to a pointer.
char **p;
We have to do more work to set this up as a 2D array, but we have a lot
more flexibility in the size of the array.
The number of rows in the array is set first, by making p point to an array
of pointers.
p = (char **)malloc(rows*sizeof(char *));
each pointer is then set to point to an array of characters.
for (i=0; i<row; i++) {
p[i] = (char *)malloc(cols*sizeof(char));
}
p is a pointer to a pointer
p[i] is a string
p[i][j] is a character
17
C-Memory
159.234
2-D Array doesn’t have to be square
We can still use the [] operator to access
elements of each array.
We do not need to allocate the same number
of characters to each string – the array does
not have to be square.
for (i=0;i<row;i++) {
p[i] = (char *)malloc((i+1)*sizeof(char));
}
When we have finished with memory
allocated from the heap, we must give it
back.
char *p;
p = (char *)malloc(80*sizeof(char));
…
free(p);
In the case of pointers to
pointers, we must be careful
to free memory in the correct
order.
for (i=0;i<row;i++) {
free(p[i]);
}
free(p);
Do not access heap memory
after it has been free'd.
18
C-Memory
159.234
How does free know how much memory to
release?
malloc has to remember how many bytes were allocated. How it does
this is not specified, but one common way is to allocate an extra 4 bytes,
at the start, that contain the size.
If we write to p[-1] at any time, then our program will explode when we
free(p)
Local variables are kept on a 'stack'. This is created each time a
function is called. The stack is destroyed when a return is executed.
The stack is not set to zero each time it is created (too expensive) – and
so local variables contain arbitrary data.
Local variables
need to be
initialised.
19
C-Memory
159.234
POINTERS
A pointer may be on the stack – but what it points to may be on
the heap. Failing to free heap memory before exiting a function
will leave memory on the heap that no longer has a pointer
pointing to it.
This memory can never be recovered – it is called a memory
leak.
Get into the habit of always freeing memory. Even when the
program exits.
20
C-Memory
159.234
POINTERS
When a function wants to change the value of an actual parameter, an
address must be passed to the function.
For strings the syntax looks ok, because the name is itself an address:
strcpy(s,“Napoleon");
…
void strcpy(char *p, char *q) {
inside strcpy we access the original using p[i].
To alter an integer the syntax is more clumsy
twice(&i);
…
void twice(int *ip) {
(*ip) = (*ip)*2;
}
21
C-Memory
159.234
POINTERS
We have to be brave to alter a pointer!
char *s;
allocate_and_check(&s);
…
void allocate_and_check(char **p) {
(*p) = (char *)malloc(80);
if ((*p) == NULL) {
…
It is a lot easier to use return values.
C++ tidies up the problems associated with malloc and free by
introducing 2 new keywords, new and delete.
Reference parameters also are a new feature, to make it easier
22
to alter arguments.
C-Memory
159.234
POINTERS & MULTIDIMENSIONAL ARRAYS
int (*x)[20];
2D INTEGER ARRAY
rather than
(x+1) automatically takes
into account the number
of elements in an array
int x[10][20];
x
…
First array
(x +1)
…
Second array
…
*(*(x +2) + 5)
Third array
(x +2)
*(x +2)+5
…
…
*(x +2)
23
See AddressArray2.cpp