-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathpointers.cpp
224 lines (171 loc) · 7.35 KB
/
pointers.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
/*
* Simple program to demonstrate a couple uses for pointers. This program was
* written so I could learn more about how to apply pointers and their syntax.
* As I'm a C novice, please don't just take this file for granted as it may
* contain errors and or bad practises.
*
* By Gerard (gerjo) Meier
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
// Some function prototypes as we're using a "One-pass compiler":
void pointersAndArrays(void);
void referencesAndVariables(void);
void referencesAndStructs(void);
void testingArrays(void);
void pointerToStruct(void);
void pointerToFunction(void);
void pointerToFunctionInStruct(void);
int multiply(int a, int b);
int add(int a, int b);
int* getArray1();
int* getArray2();
int* getArray3();
// Point of entry:
int main(int argc, char *argv[]) {
printf("Testing pointers and arrays: \n --------------------\n");
pointersAndArrays();
printf("\n\n\nTesting references and variables: \n --------------------\n");
referencesAndVariables();
printf("\n\n\nTesting references and structs: \n --------------------\n");
referencesAndStructs();
printf("\n\n\nTesting Arrays: \n --------------------\n");
testingArrays();
printf("\n\n\nTesting Pointers to Structs: \n --------------------\n");
pointerToStruct();
printf("\n\n\nTesting Pointers to functions: \n --------------------\n");
pointerToFunction();
printf("\n\n\nTesting Pointers to functions within structs (fake classes?): \n --------------------\n");
pointerToFunctionInStruct();
system("PAUSE");
return 0;
}
// Demonstrate that an array is nothing more than a bunch of memory "blocks" in a row.
void pointersAndArrays(void) {
int i;
int array[] = {0,1,2,3,4,5,6,7,8,9};
int *pointerToArray;
pointerToArray = array; // Notice the lacking &, which apparently has to be ommitted when using arrays.
for(i = 0; i < 10; ++i) {
// Using an index is the same as incrementing the pointer address. (unsure how "safe" this actually is)
assert(array[i] == *(pointerToArray + i));
printf("Values:(%i == %i) Addresses:(%i == %i)\n", array[i], *(pointerToArray + i), &array[i], (pointerToArray + i));
}
}
// Reference two variables to hold the same "value"
void referencesAndVariables(void) {
int value;
int *pointerToValue;
value = 100;
pointerToValue = &value;
value = 99;
// The address of value is the same as pointerToValue!
assert(&value == pointerToValue);
printf("%i == %i\n", &value, pointerToValue);
// The values are the same, too.
assert(value == *pointerToValue);
printf("%i == %i\n", value, *pointerToValue);
}
// Reference a variable with in a struct:
void referencesAndStructs(void) {
int value; // Some value that we'll be playing with.
struct Wrapper; // Forward declaration.
// Create some structure:
struct Wrapper {
int *pointerToValue;
} foo;
// "link" the pointer to the actual int:
foo.pointerToValue = &value; // The & makes sure we retrieve the memory address, not the memory value.
// notice the lacking * as we're setting the actual memory address, not memory value.
// Assign some values to both variables:
*foo.pointerToValue = 102; // Notice the * is used this time to access the actual memory value, and not the memory address.
value = 78; // Set the original variable.
// Variables hold the same data!
assert(value == *foo.pointerToValue);
printf("%i == %i\n", value, *foo.pointerToValue);
}
// This is how it should NOT be done. It will "probably" compile just fine,
// and "may" execute too, if you're "lucky".
int* getArray1(void) {
int array[] = {0,1,2,3,4,5,6,7,8,9}; // Privately allocated array.
// Return a pointer to a privately allocated array is not "allowed":
return array; // Will mostlikely yield a compiler "warning", not an "error".
}
// This is the right idea, however, sooner or later we might cause a buffer
// overflow and override some vital part in the memory. The memory I believe is also
// privately "allocated".
// In short: This is NOT how it should be done.
int* getArray2(void) {
int *array;
int i;
// We just "assume" that the next 9 memory blocks are free, while this will
// probably "work" most of the time, it's best to first actually allocate the
// memory (as seen in the next function)
for(i = 0; i < 10; ++i) array[i] = i;
return array;
}
// This is how it should be done. Much like the C++ new keyword, the
// memory has to be released after use via the "free(*pointer)" function. (called delete/delete[] in C++)
int* getArray3(void) {
int *array = (int*)malloc(10 * sizeof (int)); // Dynamically allocate memory (array)
int i;
if(array == NULL) abort();// The computer ran out of memory? Probably want to abort the program here.
// Fill the array:
for(i = 0; i < 10; ++i) array[i] = i;
// Do not forget to eventually release the memory, too!
return array;
}
void testingArrays(void) {
//int* array1 = getArray1(); // This will probably crash the application, or otherwise cause unexpected behavior.
//int* array2 = getArray2(); // This will probably crash the application, or otherwise cause unexpected behavior.
int* array3 = getArray3(); // The only correct function to return an int[10] array
int i;
for(i = 0; i < 10; ++i) {
assert(i == array3[i]);
// Notice how variable i remains at the same memory address!
printf("Values:(%i == %i) Addresses:(%i != %i)\n", i, array3[i], &i, &array3[i]);
}
// No memory leak in this awesome application!
free(array3);
}
void pointerToStruct(void) {
// Define some basic structure:
struct someStruct {
int a;
} myStruct;
//struct someStruct myStruct;
struct someStruct *pointerToStruct;
pointerToStruct = &myStruct; // Point the pointer towards the actual struct instance.
pointerToStruct->a = 101; // Set "a" via the pointer. (notice the -> instead of .)
myStruct.a = 102; // or set "a" directly. (notice the . instead of ->)
assert(myStruct.a == pointerToStruct->a);
printf("%i == %i\n", myStruct.a, pointerToStruct->a);
}
int multiply(int a, int b) {
return a * b;
}
int add(int a, int b) {
return a + b;
}
void pointerToFunction(void) {
// pointer to function, notice how the return types and arguments are definend.
int (*pointerToFunction) (int, int) = &multiply;
assert(multiply(3, 3) == pointerToFunction(3, 3));
//printf("%i == %i\n", multiply(3, 3), pointerToFunction(3, 3));
printf("Values:(%i == %i) Addresses:(%i == %i)\n", multiply(3, 3), pointerToFunction(3, 3), &multiply, pointerToFunction);
}
// Fancy that! functions in a struct:
void pointerToFunctionInStruct(void) {
// A simple wrapper struct for some "math" tools:
struct MathTools {
int (*multiply) (int, int);
int (*add) (int, int);
} tools;
// Point the pointers towards the functions:
tools.multiply = &multiply;
tools.add = &add;
// Assertions:
assert(tools.multiply(3, 3) == tools.add(6, 3));
printf("%i %i\n", tools.multiply(3, 3), tools.add(6, 3));
}