1 00:00:05,320 --> 00:00:08,230 In this video, we'll learn how to return a pointer from a function. 2 00:00:08,960 --> 00:00:13,520 In c++, functions can return pointers, which is a super powerful feature. 3 00:00:14,049 --> 00:00:17,049 In order to do this, we need to provide the type of the pointer 4 00:00:17,400 --> 00:00:19,970 in the function definition and in the function prototype. 5 00:00:20,620 --> 00:00:23,459 All this means is that the function will return an address 6 00:00:23,660 --> 00:00:26,889 of whatever type we specified in the function declaration. 7 00:00:28,670 --> 00:00:29,920 Let's see an example. 8 00:00:30,119 --> 00:00:32,790 In this function, we're returning a pointer to an integer. 9 00:00:33,480 --> 00:00:36,379 In this case, it'll be the value of the parameter that 10 00:00:36,380 --> 00:00:38,040 points to the largest integer. 11 00:00:38,990 --> 00:00:42,490 It's okay to return a pointer to data that's being passed into a function 12 00:00:42,650 --> 00:00:44,360 since we know that data exists. 13 00:00:44,590 --> 00:00:48,180 So in this case, we compare the two integers that the two pointers are 14 00:00:48,180 --> 00:00:52,490 pointing to and return the pointer that points to the largest integer. 15 00:00:53,260 --> 00:00:56,030 Notice that we're not comparing the pointers themselves. 16 00:00:56,160 --> 00:00:59,060 We're comparing what they're pointing to by de-referencing them. 17 00:00:59,790 --> 00:01:02,090 Pretty straightforward, but how do you call this function? 18 00:01:02,090 --> 00:01:03,280 I'll show you in the next slide. 19 00:01:05,209 --> 00:01:07,670 Here we have a simple main that calls the largest int 20 00:01:07,690 --> 00:01:08,900 function that we just wrote. 21 00:01:09,830 --> 00:01:13,460 I have two integers a and b, b is the largest with 200. 22 00:01:14,250 --> 00:01:18,030 I call largest int and pass in the addresses of a and b. 23 00:01:18,130 --> 00:01:21,150 This is correct since it expects pointers to integers. 24 00:01:21,940 --> 00:01:25,130 The function returns a pointer, which I assign to a variable named 25 00:01:25,130 --> 00:01:28,120 largest pointer which is declared as a pointer to an integer. 26 00:01:28,690 --> 00:01:33,640 So now that variable, largest pointer, points to either a or to b 27 00:01:33,730 --> 00:01:35,509 depending on which one was largest. 28 00:01:36,040 --> 00:01:37,250 In this case, it's b. 29 00:01:37,360 --> 00:01:39,830 So we de-reference the pointer, and it displays 200. 30 00:01:41,280 --> 00:01:45,240 Let's see an example where we allocate memory dynamically inside a function 31 00:01:45,460 --> 00:01:47,479 and return the address of that memory. 32 00:01:49,609 --> 00:01:53,280 Returning dynamically allocated memory from a function is a very 33 00:01:53,280 --> 00:01:55,839 common use case for returning a pointer from a function. 34 00:01:56,170 --> 00:02:00,440 In this example, we created a function called create array, and it expects 35 00:02:00,440 --> 00:02:04,649 an unsigned integer that contains the size of the array to create and 36 00:02:04,719 --> 00:02:08,139 a default parameter called init value and that's the value we're going to 37 00:02:08,530 --> 00:02:10,000 initialize all the array elements to. 38 00:02:10,960 --> 00:02:13,170 The function returns a pointer to an integer. 39 00:02:13,380 --> 00:02:16,049 Now this represents the address of that first integer 40 00:02:16,050 --> 00:02:17,539 that we dynamically created. 41 00:02:18,009 --> 00:02:19,720 You can see the code is pretty standard. 42 00:02:20,030 --> 00:02:22,770 After we create the storage, we use a for loop 43 00:02:22,770 --> 00:02:25,300 and initialize all the array elements to init value. 44 00:02:26,109 --> 00:02:29,670 Notice that I'm using pointer offset notation within the loop, but I could 45 00:02:29,670 --> 00:02:31,540 have used pointer subscript notation. 46 00:02:32,299 --> 00:02:36,010 Finally, we return new storage which is the address of that first 47 00:02:36,010 --> 00:02:38,210 integer in the newly created array. 48 00:02:38,210 --> 00:02:41,159 So how do we use this function? I'll show you in the next slide. 49 00:02:41,159 --> 00:02:47,049 In this sample code we, call create array and we pass in 100 and 20. 50 00:02:48,020 --> 00:02:51,910 That means I want 100 integers allocated dynamically on 51 00:02:51,910 --> 00:02:54,799 the heap and I want to initialize all of them to 20. 52 00:02:55,509 --> 00:02:59,450 So this function allocates the space dynamically on the heap for those 100 53 00:02:59,590 --> 00:03:04,080 integers, initializes them all to 20 and returns the address of that first 54 00:03:04,100 --> 00:03:06,810 integer, which I assigned to my array. 55 00:03:07,640 --> 00:03:09,859 Now I can use my array, however, I like. 56 00:03:10,340 --> 00:03:14,060 But remember, since the storage is on the heap, you need to release it. 57 00:03:14,280 --> 00:03:17,160 So you have to remember to use delete with the square brackets 58 00:03:17,170 --> 00:03:18,420 on that pointer variable. 59 00:03:19,510 --> 00:03:22,750 Now let's see what not to do when returning pointers from a function. 60 00:03:24,760 --> 00:03:26,100 Here I have two functions. 61 00:03:26,420 --> 00:03:29,259 The first function is called don't do this and the second 62 00:03:29,259 --> 00:03:30,739 function is called or this. 63 00:03:30,809 --> 00:03:32,669 They both return pointers to integers. 64 00:03:33,589 --> 00:03:35,979 The first function returns the address of size. 65 00:03:36,199 --> 00:03:37,280 This is a real problem. 66 00:03:37,480 --> 00:03:40,010 Size is a local variable to the function. 67 00:03:40,810 --> 00:03:44,090 This will compile just fine since the address of size is 68 00:03:44,099 --> 00:03:46,720 the address of an integer and that's what the function returns. 69 00:03:47,290 --> 00:03:48,460 But what's the problem? 70 00:03:48,719 --> 00:03:50,280 Well, you can see it's a huge problem. 71 00:03:50,500 --> 00:03:53,609 We're returning the address of a local variable in the function. 72 00:03:54,459 --> 00:03:57,560 The variable's on the stack and the function just terminated, so this 73 00:03:57,560 --> 00:03:59,490 variable is now past its lifetime. 74 00:04:00,300 --> 00:04:03,950 The next time the function is called or any function is called, the stack 75 00:04:03,950 --> 00:04:07,049 area will be reused and the pointer will now be pointing into that 76 00:04:07,049 --> 00:04:08,850 new functions activation record. 77 00:04:09,710 --> 00:04:12,489 If you overwrite the data it's pointing to, you could trash the 78 00:04:12,490 --> 00:04:16,040 stack pointers, static links, all kinds of important information 79 00:04:16,040 --> 00:04:17,170 on the activation record. 80 00:04:17,880 --> 00:04:20,829 Hopefully, the program crashes or you get a really strange 81 00:04:20,880 --> 00:04:21,959 error that you can fix. 82 00:04:22,410 --> 00:04:25,489 But if the program changes data that isn't currently being used, 83 00:04:25,809 --> 00:04:28,310 then the program may appear to work correctly for a while. 84 00:04:28,420 --> 00:04:31,750 These types of errors or bugs are very difficult to find. 85 00:04:32,550 --> 00:04:35,219 The second function has the same problem except that 86 00:04:35,220 --> 00:04:38,160 it's assigned a pointer to size variable and returns it. 87 00:04:38,330 --> 00:04:41,229 In both cases, the address that's being returned is a 88 00:04:41,230 --> 00:04:44,780 stack variable or a function local variable, very bad idea. 89 00:04:45,759 --> 00:04:47,250 Okay, that completes this video. 90 00:04:47,359 --> 00:04:50,030 You'll get a chance to work with functions that return pointers 91 00:04:50,030 --> 00:04:53,040 to dynamically allocated storage in the challenge exercise 92 00:04:53,040 --> 00:04:54,260 at the end of this section. 93 00:04:54,340 --> 00:04:57,230 But first, let's head over to the IDE, and we'll go over some 94 00:04:57,230 --> 00:04:59,099 of these functions in live code. 95 00:05:00,929 --> 00:05:01,979 Okay, so I'm in the IDE. 96 00:05:01,979 --> 00:05:05,969 I'm in the section 12 workspace in the ReturnPointer project. 97 00:05:06,480 --> 00:05:09,640 And I'd like to walk through this example when we created that create 98 00:05:09,680 --> 00:05:14,110 array function, that dynamically allocates some storage on the heap. 99 00:05:14,349 --> 00:05:15,930 So let's walk through this example. 100 00:05:16,450 --> 00:05:17,780 Right here, we're in main. 101 00:05:17,780 --> 00:05:20,630 And you'll notice that main is activated when the program 102 00:05:20,630 --> 00:05:23,699 begins, and we've got three local variables in main. 103 00:05:23,699 --> 00:05:28,740 We've got my array, which currently is just nulled out. 104 00:05:29,670 --> 00:05:33,840 We have size, which contains garbage right now. 105 00:05:33,840 --> 00:05:39,430 And we have init value, which is zeroed out at the moment. 106 00:05:40,940 --> 00:05:42,240 Okay, so what do we do? 107 00:05:42,270 --> 00:05:44,900 We ask the user how many integers would you like to allocate, 108 00:05:44,900 --> 00:05:46,180 and we read that into size. 109 00:05:46,200 --> 00:05:48,289 Let's say that they want to allocate 10 integers. 110 00:05:49,010 --> 00:05:50,280 So we'll put a 10 in here. 111 00:05:50,900 --> 00:05:53,630 And then what value would would you like to initialize to? 112 00:05:53,740 --> 00:05:57,489 How about we initialize them all to number to the two. 113 00:05:58,680 --> 00:06:00,220 So now we've got those variables. 114 00:06:00,510 --> 00:06:04,650 And what we do now is we call create array and we pass in 115 00:06:04,650 --> 00:06:07,000 the size and the initial value. 116 00:06:07,570 --> 00:06:09,909 So we're here now, here's the function create array. 117 00:06:10,110 --> 00:06:16,110 Notice create array has one, two, three local variables, right. 118 00:06:16,150 --> 00:06:21,020 It's got size, and let me call create array here. 119 00:06:22,630 --> 00:06:26,386 So I'm calling create array with the size, which is 10 and 120 00:06:26,386 --> 00:06:27,920 the initial value which is 2. 121 00:06:27,920 --> 00:06:30,700 If i didn't supply an initial value, it would use 0. 122 00:06:30,700 --> 00:06:32,480 There's the default initializer here. 123 00:06:32,950 --> 00:06:36,870 But in this case, size is 10 initial value. 124 00:06:37,420 --> 00:06:39,850 And notice again, I'm using the same variable names. 125 00:06:39,850 --> 00:06:42,180 I'm doing that on purpose don't let that confuse you, 2. 126 00:06:43,970 --> 00:06:49,740 And then we've got new storage right here which is a pointer to an integer. 127 00:06:50,480 --> 00:06:53,250 That's where we're going to allocate the memory from when we call 128 00:06:53,250 --> 00:06:54,549 new right here on the next line. 129 00:06:55,190 --> 00:06:56,140 And right now that's null. 130 00:06:57,360 --> 00:07:00,960 Okay, so now new storage equals new int size. 131 00:07:00,970 --> 00:07:03,200 How many integers do I want to allocate dynamically? 132 00:07:03,320 --> 00:07:04,919 However, many integers were passed in? 133 00:07:04,920 --> 00:07:05,960 In this case, 10. 134 00:07:06,590 --> 00:07:09,459 So 10 integers will be allocated dynamically on 135 00:07:09,460 --> 00:07:11,040 the heap, not on the stack. 136 00:07:11,040 --> 00:07:11,819 This is the stack. 137 00:07:11,820 --> 00:07:13,400 The heap is a different part of memory. 138 00:07:13,870 --> 00:07:17,219 It's way up here, let's say, and we're going to allocate 10 139 00:07:17,219 --> 00:07:21,750 integers, 0 through 9, on the heap. 140 00:07:21,770 --> 00:07:23,680 Let's say that this is address 5000. 141 00:07:24,330 --> 00:07:26,880 That's the address of that very first integer right here. 142 00:07:27,960 --> 00:07:31,440 What's being returned and assigned to new storage is 143 00:07:31,460 --> 00:07:32,990 that first integers address. 144 00:07:32,990 --> 00:07:34,890 So we're putting a 5000 in here. 145 00:07:35,240 --> 00:07:36,360 There's our pointer. 146 00:07:36,900 --> 00:07:38,070 Now this is real important. 147 00:07:38,080 --> 00:07:40,120 We've got a pointer on the stack. 148 00:07:40,150 --> 00:07:41,990 That's pointing to storage on the heap. 149 00:07:42,250 --> 00:07:43,760 This is exactly what we want. 150 00:07:44,130 --> 00:07:46,120 We've got to be careful, not to lose that pointer. 151 00:07:46,120 --> 00:07:48,720 If we lose that pointer, we've got a memory leak. 152 00:07:49,380 --> 00:07:50,460 Okay, great. 153 00:07:50,710 --> 00:07:53,740 So now we have that memory allocated, and we want to initialize it. 154 00:07:53,740 --> 00:07:56,920 Remember right now that all that is garbage data right in here. 155 00:07:57,590 --> 00:07:58,290 So what do we do? 156 00:07:58,320 --> 00:07:59,780 We just use a simple for loop. 157 00:07:59,780 --> 00:08:01,750 We're going from 0 less than size by 1. 158 00:08:02,800 --> 00:08:06,710 And we're initializing every element in this array to whatever was being 159 00:08:06,710 --> 00:08:08,510 passed in an initial value right here. 160 00:08:08,510 --> 00:08:09,740 In this case, we passed in a 2. 161 00:08:10,620 --> 00:08:12,180 So we're going to store 2 everywhere. 162 00:08:12,510 --> 00:08:15,630 And here, I'm using pointer offset notation. 163 00:08:15,670 --> 00:08:19,620 I could have just said new storage sub-I and use pointer array 164 00:08:19,620 --> 00:08:22,650 notation or pointer subscript notation, either one is fine. 165 00:08:23,139 --> 00:08:27,190 So in this case, we're putting a 2 in all of these guys. 166 00:08:27,490 --> 00:08:30,320 All 10 of them will have 2s in them. 167 00:08:31,270 --> 00:08:33,090 And now, this is the piece that's really important. 168 00:08:33,099 --> 00:08:34,679 We return new storage. 169 00:08:34,760 --> 00:08:35,860 But what's new storage? 170 00:08:35,880 --> 00:08:36,828 It's 5000. 171 00:08:36,990 --> 00:08:40,750 We return that value 5000 and notice in main, we're 172 00:08:40,750 --> 00:08:42,320 assigning it to my array. 173 00:08:44,720 --> 00:08:46,320 So we're putting a 5000 in here. 174 00:08:46,510 --> 00:08:50,370 So now this pointer is pointing to the same place. 175 00:08:50,380 --> 00:08:54,260 That's really important because this function is almost done. 176 00:08:54,480 --> 00:08:57,430 So when this function gets popped off the stack, we're going to 177 00:08:57,430 --> 00:08:59,769 lose this pointer, right here. 178 00:09:00,539 --> 00:09:02,830 And we don't want to lose that pointer, so that's why 179 00:09:02,830 --> 00:09:04,040 we assign it to my array. 180 00:09:04,040 --> 00:09:06,540 So now we've got a copy of that pointer that we can use. 181 00:09:06,950 --> 00:09:07,940 Okay, good. 182 00:09:07,960 --> 00:09:10,500 So at this point, the function is now done. 183 00:09:11,059 --> 00:09:13,479 We start cleaning it up. 184 00:09:13,940 --> 00:09:16,599 So all this is gone now, right. 185 00:09:16,609 --> 00:09:18,300 So this pointer here is now gone. 186 00:09:18,730 --> 00:09:19,910 We lose all this. 187 00:09:21,170 --> 00:09:22,280 And we're back to main. 188 00:09:23,390 --> 00:09:25,570 Now notice main has that pointer. 189 00:09:25,570 --> 00:09:27,500 So we didn't lose our memory out on the heap. 190 00:09:27,719 --> 00:09:29,360 That's really important to understand. 191 00:09:30,290 --> 00:09:32,580 Okay, so now, let's display the data. 192 00:09:32,900 --> 00:09:40,180 So I'm calling this function right now, display, and I'm passing in, in 193 00:09:40,180 --> 00:09:43,150 this case, my array, my array is 5000. 194 00:09:45,240 --> 00:09:47,989 That's the value of that pointer and the size, which was 10. 195 00:09:49,559 --> 00:09:54,890 Okay, So display now gets activated on the stack, and it's got 1, right 196 00:09:54,890 --> 00:09:58,270 here, variable, 1 local variable another local variable and it's 197 00:09:58,270 --> 00:09:59,840 got another variable right here I. 198 00:10:00,150 --> 00:10:01,290 Okay, I'm not going to worry about I. 199 00:10:01,290 --> 00:10:03,440 You know all about I, it's just a looping variable. 200 00:10:03,660 --> 00:10:09,030 So it's going to have this variable array and it's going to have a size. 201 00:10:09,690 --> 00:10:14,910 Okay, so 5000 gets copied to array, 10 gets copied to size. 202 00:10:15,180 --> 00:10:20,260 Notice that this is now pointing to that same place, but it's constant. 203 00:10:20,280 --> 00:10:23,060 We've got a constant pointer, and we're pointing to a constant array. 204 00:10:23,060 --> 00:10:26,770 So we can't mess with that array either by accident or intentionally. 205 00:10:27,849 --> 00:10:30,819 And all we're doing is we're just looping through there and displaying 206 00:10:30,820 --> 00:10:32,089 out every element in the array. 207 00:10:32,250 --> 00:10:37,580 Notice that in this case I'm using pointer subscript notation here. 208 00:10:37,580 --> 00:10:41,499 Whereas, over here, I use pointer offset notation, same exact thing. 209 00:10:42,250 --> 00:10:44,699 So this function now goes through there, displays 210 00:10:44,730 --> 00:10:47,120 all those 2s 10 of them. 211 00:10:47,490 --> 00:10:52,160 When we're done, same as before, we basically start unwinding. 212 00:10:52,160 --> 00:10:52,930 So this is done. 213 00:10:52,930 --> 00:10:56,110 After we do all the displaying, we're gone here. 214 00:10:57,570 --> 00:10:59,360 This is gone, and we're back to main. 215 00:11:00,059 --> 00:11:02,949 Now I've got the storage allocated on the heap. 216 00:11:03,480 --> 00:11:04,280 I'm done with it. 217 00:11:04,309 --> 00:11:07,010 I need to release it or free it up, and that's what's 218 00:11:07,010 --> 00:11:08,990 happening right here at line 34. 219 00:11:10,930 --> 00:11:13,410 Delete square brackets and the name of the pointer. 220 00:11:13,720 --> 00:11:16,829 You've got to make sure that the value of that pointer is 221 00:11:16,830 --> 00:11:18,130 something that was newed. 222 00:11:18,460 --> 00:11:22,300 Okay, you just can't point to like a stack reference and then delete that. 223 00:11:22,549 --> 00:11:25,709 So in this case, this will now be freed up. 224 00:11:25,860 --> 00:11:28,060 And that memory will be ready to be used again. 225 00:11:30,650 --> 00:11:33,230 So let's clear this up and give it a run. 226 00:11:34,969 --> 00:11:36,209 So we'll build and run here. 227 00:11:36,500 --> 00:11:40,070 So let's say we want to allocate 10 integers, and we 228 00:11:40,070 --> 00:11:41,680 want to set all of them to 5. 229 00:11:42,840 --> 00:11:45,790 There you see, we're displaying all 10 integers, each one 230 00:11:45,790 --> 00:11:47,370 is set to 5, pretty easy. 231 00:11:47,580 --> 00:11:48,530 Let's run this again. 232 00:11:49,040 --> 00:11:53,189 And suppose we want to allocate a 1000 integers this time, and we want to set 233 00:11:53,190 --> 00:11:55,390 each one of them to, I don't know, 88. 234 00:11:57,170 --> 00:12:00,320 We run it, there we get a 1000 integers, all set to 98. 235 00:12:00,600 --> 00:12:02,990 What's important to understand here is that it's all on the 236 00:12:02,990 --> 00:12:04,900 heap, which is pretty cool. 237 00:12:05,440 --> 00:12:07,699 Okay, so that finishes off this video. 238 00:12:07,870 --> 00:12:09,079 I hope this makes a lot of sense. 239 00:12:09,080 --> 00:12:10,640 If you have any questions, please let me know.