1 // section_8.cpp : Defines the entry point for the console application. 2 //范磊 C++ 第8章 指针 3 //指针本质也是一个变量,只是这个变量存放的数据比较特殊,怎么特殊? 4 //里面存放的是别人家的地址. 其他变量的内存编号而已. 5 6 #include "stdafx.h" 7 #include "iostream" 8 9 using namespace std; 10 11 //-------------------------------------------------- 12 //8.1 地址 13 //地址,可以理解为:每一个内存都有自己的空间编号,这个编号称为"地址" 14 void fun1() 15 { 16 int i; 17 18 i = 1; 19 cout << &i << endl ; // &是取地址符号,在变量名字前面 +&,表示获得这个变量 i 的内存编号. 20 } //c++直接回输出一个16进制的数字.不向c那样,前面要 %x 表示16进制. 21 22 23 //-------------------------------------------------- 24 //8.2 用指针来保存地址 25 //用一个特别的变量(指针)去存放其他变量的内存地址. 26 void fun2() 27 { 28 int a; 29 int* p; 30 31 p = &a; 32 cout << &a << endl; //打印出变量a的地址 0018ffe0 33 cout << p << endl; //打印出变量a的地址 0018ffe0,所以说指针p 保存了变量a的地址. 34 } 35 36 37 //------------------------------------------------- 38 //8.21 空指针(好像不是很适合叫空指针) 39 //当我们定义了一个指针后,如果不初始化,这个"迷途指针"里面的内容是一个随机数 40 //所以我们要给指针赋值,赋个0给他. 41 void fun3() 42 { 43 int* p; 44 p = 0; 45 cout << "p: " << p << endl; 46 } 47 48 49 //------------------------------------------------- 50 //8.2.3 用指针来访问值 51 // 符号 * 称为指针运算符. 意思是取出指针里面的地址的内容. 52 //例如 指针p = 1234567 ,*p 的意思就是 取出内存地址单元编号为1234567 里面的内容. 53 //汇编理解: mov Exr, ds:[1234567] 54 void fun4() 55 { 56 int a; 57 int* p; 58 59 a = 1; 60 p = &a; 61 62 cout << "&a的值为:" << " " << &a << endl ; 63 cout << "a的值为:" << " " << a << endl ; 64 cout << "p的值为:" << " " << p << endl ; 65 cout << "*p的值为:" << " " << *p << endl; 66 } 67 //打印的结构是 a == 1 , *p == 1. 68 69 70 //------------------------------------------------- 71 //8.2.4 指针地址,指针保存的地址和该地址的值 72 //指针的地址: 因为指针的本质其实也是一个变量,这个变量肯定占用内存空间,肯定有内存单元编号 73 //指针保存的地址:指针里面存放的数据,这个数据不是一般普通数据,这个数据是其他内存的单元编号(地址). 74 //该地址的值:可以通过指针里面的地址,按照地址去找到那个内存,看看里面放的是什么数据. 75 void fun5() 76 { 77 int i; 78 int* p; 79 80 cout << "i的地址为: " << &i << endl ; 81 cout << "p的值为: " << p << endl ; //此时p还没赋值,属于一个"迷途指针" 82 cout << "p的地址为: " << &p << endl ; //p虽然是迷途指针,但前面已经进行int* p 声明了. 83 //所以p也有自己的地址. 84 i = 3; 85 cout << "i赋值后的地址为: " << &i << endl ; 86 87 p = &i; //把 i 的地址告诉了p. 88 cout << "p赋值后的值为: " << p << endl ; //p里面存放就是i的地址. 89 cout << "p赋值后的地址为: " << &p << endl ; 90 91 } 92 93 94 //------------------------------------------------- 95 //8.2.5 指针对数值的操作 96 //可以通过 * 号,间接访问或读取指针的保存的地址里面的数据 97 typedef unsigned short int ut; //因为unsigned short int 这个类型名字很长,另外起了个小名 ut 98 void fun6() 99 { 100 //cout << sizeof(ut) << endl ; //测试一下ut是占用了多大内存空间 101 ut i; 102 ut* p = 0; 103 104 i = 5; 105 p = &i; //自从当执行p = &i以后, 改变了*p就是改变了i,改变了i就是改变了*p 106 107 cout << "i = " << i << endl ; 108 cout << "*p = " << *p << endl; 109 110 cout << "用指针来修改存放在i中的数据... " ; 111 *p = 90; 112 cout << "i = " << i << endl ; 113 cout << "*p = " << *p << endl; 114 115 cout << "用i来修改存放在i中的数据... " ; 116 i = 9; 117 cout << "i = " << i << endl ; 118 cout << "*p = " << *p << endl; 119 } 120 121 122 //------------------------------------------------- 123 //8.2.6 更换指针保存的地址 124 //平时,小明口袋里放着怎么去小芳家的地图,所以他只知道小芳家有什么东西. 125 //今天他口袋了放的是去小李家的地图,所以他只知道小李家有什么东西.不知道小芳家有什么东西. 126 void fun7() 127 { 128 int i; 129 int j; 130 int* p; 131 132 i = 10; 133 j = 20; 134 p = &i; //p存放着的是i的地址,所以p知道i里面有什么东西. 135 136 cout << "i:" << " " << i <<endl ; 137 cout << "&i:" << " " << &i << endl ; 138 cout << "j:" << " " << j <<endl ; 139 cout << "&j:" << " " << &j << endl ; 140 cout << "p:" << " " << p <<endl ; 141 cout << "*p:" << " " << *p << endl ; //*p获得就是i的内存里面的内容. 142 143 p = &j; //p存放着的是j的地址,所以p知道j里面有什么东西. 144 145 cout << "更换地址后... " ; 146 cout << "i:" << " " << i <<endl ; 147 cout << "&i:" << " " << &i << endl ; 148 cout << "j:" << " " << j <<endl ; 149 cout << "&j:" << " " << &j << endl ; 150 cout << "p:" << " " << p <<endl ; 151 cout << "*p:" << " " << *p << endl ; //*p获得就是j的内存里面的内容. 152 } 153 154 155 //------------------------------------------------- 156 //8.3.2 用指针创建堆中空间 157 //什么叫堆?(3个特点):1.堆是一大堆不连续的内存区域;2.堆生存的时间要比栈长;3.堆要手动申请,手动释放; 158 //C++中,用关键字 new 创建一个堆,并分配内存. 159 void fun8() 160 { 161 int* p; 162 p = new int; //这里如果直接写 new int 是不会报错的,但不能运行.为什么? 163 //堆是一大堆大小不连续的内存区域,在系统中由链表串接起来使用,堆中的每个内存单元都是 164 //匿名的,因此必须先在对堆中申请一个内存单元地址,然后保存在一个指针中,只有使用该指针 165 //才能访问到该内存单元的数据. 166 *p = 4; 167 cout << *p << endl ; //堆的内容 168 cout << "p: " << p << endl; //堆的地址 169 cout << "&p: " << &p << endl; 170 } 171 //函数的框架是esp-48h,多了的8个字节是怎么来? 172 //int* p 这里多了4个字节. 另外是 new int 这里也多了4个字节. 173 174 175 //------------------------------------------------- 176 //8.3.3 用指针删除堆中空间(成也萧何败也萧何) 177 //C++中,用关键字 delete 释放堆的空间.否则的话,会造成内存泄露. 178 //什么叫内存泄露? 179 //堆的地址一定是在指针里面的,只有指针才知道怎么去找到堆.如果指针丢了,那么其他任何途径都找不到这个堆了. 180 //一个宝藏地图只有小明知道,但是小明死了,其他人永远也别想找到宝藏的位置了. 181 void fun9() 182 { 183 int* p; 184 p = new int; 185 *p = 3600; 186 187 cout << *p << endl ; 188 189 delete p; 190 cout << *p << endl ; //p已经变成了迷途指针了. 191 192 p = 0; 193 p = new int; 194 *p = 8; 195 cout << *p << endl ; 196 197 delete p; 198 cout << *p << endl ; 199 } 200 201 202 //------------------------------------------------- 203 //8.4.2 在堆中删除对象 204 class A 205 { 206 private: 207 int i; 208 public: 209 A() 210 { 211 cout << "构造函数执行中... " ; 212 i = 0x999; 213 } 214 ~A() 215 { 216 cout << "析构造函数执行中... " ; 217 } 218 int get() 219 { 220 return i; 221 } 222 }; 223 void fun10() 224 { 225 A* p; 226 p = new A; 227 delete p; 228 } 229 //函数框架不明白. 230 231 232 233 //------------------------------------------------- 234 //8.4.4 访问对中的数据成员 235 //必须要通过指针才能访问堆. 236 class A1 237 { 238 private: 239 int i; 240 public: 241 int get() const 242 { 243 return i; 244 } 245 void set(int x) 246 { 247 i = x; 248 } 249 }; 250 void fun11() 251 { 252 A1* a; 253 a = new A1; 254 a->set(66); //通过 -> 符号来访问堆. 255 cout << a->get() << endl ; 256 delete a; 257 } 258 259 260 //------------------------------------------------- 261 //8.4.5 在构造函数中开辟内存空间 262 class A2 263 { 264 private: 265 int* i; 266 public: 267 A2(); 268 ~A2(); 269 int get() const 270 { 271 return *i; 272 } 273 void set(int x) 274 { 275 *i = x; 276 } 277 }; 278 void fun12() 279 { 280 A2* p; 281 p = new A2; 282 cout << p->get() << endl ; 283 p->set(0) ; 284 cout << p->get() << endl ; 285 delete p ; 286 } 287 A2::A2() 288 { 289 cout << "构造函数执行中... " ; 290 i = new int(999) ; 291 } 292 A2::~A2() 293 { 294 cout << "析构函数执行中... " ; 295 delete i ; 296 } 297 298 299 //------------------------------------------------- 300 //8.4.6 对象在栈与堆中的不同 301 class A3 302 { 303 private: 304 int* i; 305 public: 306 A3(); 307 ~A3(); 308 int get() const //const加在这里什么意思? 309 { 310 return *i; 311 } 312 void set(int x) 313 { 314 *i = x; 315 } 316 }; 317 void fun13() 318 { 319 A3* p; 320 p = new A3; //开辟新的内存空间,空间的首地址放到了p里面.? 321 cout << p->get() << endl ; 322 p->set(123); 323 cout << p->get() << endl ; 324 } 325 A3::A3() 326 { 327 cout << "构造函数执行中... " ; 328 i = new int(999) ; 329 } 330 A3::~A3() 331 { 332 cout << "析构函数执行中... " ; 333 delete i ; 334 } 335 336 337 //------------------------------------------------- 338 //8.5 this指针 339 //this指针记录每个对象的内存地址,然后通过间接引用符 -> 访问该对象的成员. 340 class A4 341 { 342 private: 343 int i; 344 public: 345 int get() const 346 { 347 return i; 348 } 349 void set(int x) 350 { 351 this-> i; 352 i = x; 353 cout << "this变量保存的内存地址: " << this << endl ; 354 } 355 }; 356 357 void fun14() 358 { 359 A4 a; 360 a.set(99); 361 cout << "对象a的内存地址: " << &a << endl; 362 cout << a.get() << endl; 363 364 A4 b; 365 b.set(9999); 366 cout << "对象b的内存地址: " << &b << endl; 367 cout << b.get() << endl; 368 369 } 370 371 372 373 //------------------------------------------------- 374 //8.6 指针的常见错误 375 //删除一个指针后,一定要将该指针设定为赋值为0.因为删除该指针只会释放它指向的内存空间,不会删除指针. 376 //因此这个指针还存在,并且仍会指向原来的内存空间,这时如果再次尝试使用该指针,将导致程序出错. 377 void fun15() 378 { 379 int* p; 380 p = new int; 381 *p =3; 382 383 cout << "将3赋值给p的地址后,指针p读取的值: " << *p << endl ; 384 delete p; 385 cout << "删除空间后,指针p读取的值: " << *p << endl ; 386 387 long* p1; 388 p1 = new long; 389 cout << "创建新空间后,指针p中的保存地址: " << p << endl; 390 *p1 = 99999; 391 cout << "指向新空间的指针p1保存的地址: " << p1 << endl; 392 *p = 23; 393 cout << "将23赋值给p的地址后,指针p读取的值: " << *p << endl; 394 cout << "将23赋值给p的地址后,指针p1读取的值: " << *p1 << endl; 395 delete p1; 396 } 397 398 399 //------------------------------------------------- 400 //8.7.1 指针的加减运算 401 void fun16() 402 { 403 int* p; 404 p = new int; 405 cout << "指针p保存的空间地址为: " << p << endl ; 406 p++; 407 cout << "自加后,指针p保存的空间地址为: " << p << endl ; 408 p--; 409 cout << "自减后,指针p保存的空间地址为: " << p << endl ; 410 p -= 2; 411 cout << "减2后,指针p保存的空间地址为: " << p << endl ; 412 } 413 414 415 416 //------------------------------------------------- 417 //8.7.2 指针的赋值运算 418 void fun17() 419 { 420 int* p; 421 p = new int; 422 cout << "p:" << p << endl; 423 int* p1; 424 p1 = new int; 425 cout << "p1:" << p1 << endl; 426 p = p1; 427 cout << "赋值后... " ; 428 cout << "p:" << p << endl; 429 } 430 431 432 //------------------------------------------------- 433 //8.7.3 指针的相减运算 434 void fun18() 435 { 436 int* p; 437 p = new int; 438 cout << "p:" << p << endl; 439 int* p1; 440 p1 = new int; 441 cout << "p1:" << p1 << endl ; 442 *p = p - p1; //两个地址相减,得出的是一个数字. 443 cout << "两个内存的地址差: " ; 444 cout << *p << endl; 445 } 446 447 448 449 //------------------------------------------------- 450 //8.7.4 指针的比较运算 451 void fun19() 452 { 453 int* p; 454 p = new int; 455 cout << "p:" << p << endl ; 456 int *p1; 457 p1 = new int; 458 cout << "p1:" << p1 << endl ; 459 if(p > p1) 460 { 461 cout << "p大于p1的内存地址. " ; 462 } 463 else 464 { 465 cout << "p1大于p的内存地址. " ; 466 } 467 468 } 469 470 471 //------------------------------------------------- 472 //8.8.1 常量指针 473 //常量指针:指针的值不能改变. 这个指针是一个常量,是一个不变量. 474 class A5 475 { 476 private: 477 int i; 478 public: 479 int get() const 480 { 481 return i; 482 } 483 void set(int x) 484 { 485 i = x; 486 } 487 }; 488 void fun20() 489 { 490 A5* p; 491 p = new A5; 492 cout << "p:" << p << endl ; 493 p += 1; 494 cout << "p:" << p << endl ; 495 496 A5* const p1 = new A5; //error C2734: 'p1' : const object must be initialized if not extern 497 //p1 = new A5; 不能再这样写了.报上面的错. 498 //p1 += 1; //因为前面const p1说明了p1是不能改变的.如果非要执行这句的话,编译出错. 499 p1->set(6); 500 cout << p1->get() << endl; 501 502 } 503 504 505 506 //------------------------------------------------- 507 //8.8.2 指向常量的指针 508 class A6 509 { 510 private: 511 int i; 512 public: 513 int get() const 514 { 515 return i; 516 } 517 void set(int x) 518 { 519 i = x; 520 } 521 }; 522 void fun21() 523 { 524 const A6* p; // const(A6* p) ,说明这个(A6* p)的值是一个常量. 525 p = new A6; 526 p += 1; 527 //p->set(11); 528 cout << p->get() << endl ; 529 } 530 531 532 //------------------------------------------------- 533 //8.8.3 指向常量的常指针 534 class A7 535 { 536 private: 537 int i; 538 public: 539 int get() const 540 { 541 return i; 542 } 543 void set(int x) 544 { 545 i = x; 546 } 547 }; 548 void fun22() 549 { 550 const A7* const p = new A7; //'p' : const object must be initialized if not extern 551 //p = new A7; //不能这样写了. 552 //p += 1; //因为指针是常量,所以这里要进行指针改变,不能通过编译. 553 //p->set(11); //因为指针指向的内容页是常量,所以这里要进行修改,也不能通过编译. 554 cout << p->get() << endl ; 555 } 556 557 558 //////////////////////第8章主要例子完毕/////////////////////// 559 560 561 int main(int argc, char* argv[]) 562 { 563 //fun1(); //8.1 地址 564 //fun2(); //8.2 用指针来保存地址 565 //fun3(); //8.2.1 空指针 566 //fun4(); //8.2.3 用指针来访问值 567 //fun5(); //8.2.4 指针地址,指针保存的地址和该地址的值 568 //fun6(); //8.2.5 指针对数值的操作 569 //fun7(); //8.2.6 更换指针保存的地址 570 //fun8(); //8.3.2 用指针创建堆中空间 571 //fun9(); //8.3.3 用指针删除堆中空间 572 //fun10(); //8.4.2 在堆中删除对象 573 //fun11(); //8.4.4 访问对中的数据成员 574 //fun12(); //8.4.5 在构造函数中开辟内存空间(不明白) 575 //fun13(); //8.4.6 对象在栈与堆中的不同(不明白) 576 //fun14(); //8.5 this指针 577 //fun15(); //8.6 指针的常见错误 578 //fun16(); //8.7.1 指针的加减运算 579 //fun17(); //8.7.2 指针的赋值运算 580 //fun18(); //8.7.3 指针的相减运算 581 //fun19(); //8.7.4 指针的比较运算 582 //fun20(); //8.8.1 常量指针 583 //fun21(); //8.8.2 指向常量的指针 584 //fun22(); //8.8.3 指向常量的常指针 585 586 return 0; 587 }