Files
makefile_cpp/POINTER/指针.html
2024-01-21 18:25:54 +08:00

2737 lines
222 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html><html lang="en"><head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>C/C++指针专题</title>
<style>
@font-face {
font-family: octicons-link;
src: url(data:font/woff;charset=utf-8;base64,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) format('woff');
}
.markdown-body .octicon {
display: inline-block;
fill: currentColor;
vertical-align: text-bottom;
}
.markdown-body .anchor {
float: left;
line-height: 1;
margin-left: -20px;
padding-right: 4px;
}
.markdown-body .anchor:focus {
outline: none;
}
.markdown-body h1 .octicon-link,
.markdown-body h2 .octicon-link,
.markdown-body h3 .octicon-link,
.markdown-body h4 .octicon-link,
.markdown-body h5 .octicon-link,
.markdown-body h6 .octicon-link {
color: #1b1f23;
vertical-align: middle;
visibility: hidden;
}
.markdown-body h1:hover .anchor,
.markdown-body h2:hover .anchor,
.markdown-body h3:hover .anchor,
.markdown-body h4:hover .anchor,
.markdown-body h5:hover .anchor,
.markdown-body h6:hover .anchor {
text-decoration: none;
}
.markdown-body h1:hover .anchor .octicon-link,
.markdown-body h2:hover .anchor .octicon-link,
.markdown-body h3:hover .anchor .octicon-link,
.markdown-body h4:hover .anchor .octicon-link,
.markdown-body h5:hover .anchor .octicon-link,
.markdown-body h6:hover .anchor .octicon-link {
visibility: visible;
}
.markdown-body {
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
color: #24292e;
line-height: 1.5;
font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;
font-size: 16px;
line-height: 1.5;
word-wrap: break-word;
}
.markdown-body .pl-c {
color: #6a737d;
}
.markdown-body .pl-c1,
.markdown-body .pl-s .pl-v {
color: #005cc5;
}
.markdown-body .pl-e,
.markdown-body .pl-en {
color: #6f42c1;
}
.markdown-body .pl-s .pl-s1,
.markdown-body .pl-smi {
color: #24292e;
}
.markdown-body .pl-ent {
color: #22863a;
}
.markdown-body .pl-k {
color: #d73a49;
}
.markdown-body .pl-pds,
.markdown-body .pl-s,
.markdown-body .pl-s .pl-pse .pl-s1,
.markdown-body .pl-sr,
.markdown-body .pl-sr .pl-cce,
.markdown-body .pl-sr .pl-sra,
.markdown-body .pl-sr .pl-sre {
color: #032f62;
}
.markdown-body .pl-smw,
.markdown-body .pl-v {
color: #e36209;
}
.markdown-body .pl-bu {
color: #b31d28;
}
.markdown-body .pl-ii {
background-color: #b31d28;
color: #fafbfc;
}
.markdown-body .pl-c2 {
background-color: #d73a49;
color: #fafbfc;
}
.markdown-body .pl-c2:before {
content: "^M";
}
.markdown-body .pl-sr .pl-cce {
color: #22863a;
font-weight: 700;
}
.markdown-body .pl-ml {
color: #735c0f;
}
.markdown-body .pl-mh,
.markdown-body .pl-mh .pl-en,
.markdown-body .pl-ms {
color: #005cc5;
font-weight: 700;
}
.markdown-body .pl-mi {
color: #24292e;
font-style: italic;
}
.markdown-body .pl-mb {
color: #24292e;
font-weight: 700;
}
.markdown-body .pl-md {
background-color: #ffeef0;
color: #b31d28;
}
.markdown-body .pl-mi1 {
background-color: #f0fff4;
color: #22863a;
}
.markdown-body .pl-mc {
background-color: #ffebda;
color: #e36209;
}
.markdown-body .pl-mi2 {
background-color: #005cc5;
color: #f6f8fa;
}
.markdown-body .pl-mdr {
color: #6f42c1;
font-weight: 700;
}
.markdown-body .pl-ba {
color: #586069;
}
.markdown-body .pl-sg {
color: #959da5;
}
.markdown-body .pl-corl {
color: #032f62;
text-decoration: underline;
}
.markdown-body details {
display: block;
}
.markdown-body summary {
display: list-item;
}
.markdown-body a {
background-color: transparent;
}
.markdown-body a:active,
.markdown-body a:hover {
outline-width: 0;
}
.markdown-body strong {
font-weight: inherit;
font-weight: bolder;
}
.markdown-body h1 {
font-size: 2em;
margin: .67em 0;
}
.markdown-body img {
border-style: none;
}
.markdown-body code,
.markdown-body kbd,
.markdown-body pre {
font-family: monospace,monospace;
font-size: 1em;
}
.markdown-body hr {
box-sizing: content-box;
height: 0;
overflow: visible;
}
.markdown-body input {
font: inherit;
margin: 0;
}
.markdown-body input {
overflow: visible;
}
.markdown-body [type=checkbox] {
box-sizing: border-box;
padding: 0;
}
.markdown-body * {
box-sizing: border-box;
}
.markdown-body input {
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
.markdown-body a {
color: #0366d6;
text-decoration: none;
}
.markdown-body a:hover {
text-decoration: underline;
}
.markdown-body strong {
font-weight: 600;
}
.markdown-body hr {
background: transparent;
border: 0;
border-bottom: 1px solid #dfe2e5;
height: 0;
margin: 15px 0;
overflow: hidden;
}
.markdown-body hr:before {
content: "";
display: table;
}
.markdown-body hr:after {
clear: both;
content: "";
display: table;
}
.markdown-body table {
border-collapse: collapse;
border-spacing: 0;
}
.markdown-body td,
.markdown-body th {
padding: 0;
}
.markdown-body details summary {
cursor: pointer;
}
.markdown-body h1,
.markdown-body h2,
.markdown-body h3,
.markdown-body h4,
.markdown-body h5,
.markdown-body h6 {
margin-bottom: 0;
margin-top: 0;
}
.markdown-body h1 {
font-size: 32px;
}
.markdown-body h1,
.markdown-body h2 {
font-weight: 600;
}
.markdown-body h2 {
font-size: 24px;
}
.markdown-body h3 {
font-size: 20px;
}
.markdown-body h3,
.markdown-body h4 {
font-weight: 600;
}
.markdown-body h4 {
font-size: 16px;
}
.markdown-body h5 {
font-size: 14px;
}
.markdown-body h5,
.markdown-body h6 {
font-weight: 600;
}
.markdown-body h6 {
font-size: 12px;
}
.markdown-body p {
margin-bottom: 10px;
margin-top: 0;
}
.markdown-body blockquote {
margin: 0;
}
.markdown-body ol,
.markdown-body ul {
margin-bottom: 0;
margin-top: 0;
padding-left: 0;
}
.markdown-body ol ol,
.markdown-body ul ol {
list-style-type: lower-roman;
}
.markdown-body ol ol ol,
.markdown-body ol ul ol,
.markdown-body ul ol ol,
.markdown-body ul ul ol {
list-style-type: lower-alpha;
}
.markdown-body dd {
margin-left: 0;
}
.markdown-body code,
.markdown-body pre {
font-family: SFMono-Regular,Consolas,Liberation Mono,Menlo,Courier,monospace;
font-size: 12px;
}
.markdown-body pre {
margin-bottom: 0;
margin-top: 0;
}
.markdown-body input::-webkit-inner-spin-button,
.markdown-body input::-webkit-outer-spin-button {
-webkit-appearance: none;
appearance: none;
margin: 0;
}
.markdown-body .border {
border: 1px solid #e1e4e8!important;
}
.markdown-body .border-0 {
border: 0!important;
}
.markdown-body .border-bottom {
border-bottom: 1px solid #e1e4e8!important;
}
.markdown-body .rounded-1 {
border-radius: 3px!important;
}
.markdown-body .bg-white {
background-color: #fff!important;
}
.markdown-body .bg-gray-light {
background-color: #fafbfc!important;
}
.markdown-body .text-gray-light {
color: #6a737d!important;
}
.markdown-body .mb-0 {
margin-bottom: 0!important;
}
.markdown-body .my-2 {
margin-bottom: 8px!important;
margin-top: 8px!important;
}
.markdown-body .pl-0 {
padding-left: 0!important;
}
.markdown-body .py-0 {
padding-bottom: 0!important;
padding-top: 0!important;
}
.markdown-body .pl-1 {
padding-left: 4px!important;
}
.markdown-body .pl-2 {
padding-left: 8px!important;
}
.markdown-body .py-2 {
padding-bottom: 8px!important;
padding-top: 8px!important;
}
.markdown-body .pl-3,
.markdown-body .px-3 {
padding-left: 16px!important;
}
.markdown-body .px-3 {
padding-right: 16px!important;
}
.markdown-body .pl-4 {
padding-left: 24px!important;
}
.markdown-body .pl-5 {
padding-left: 32px!important;
}
.markdown-body .pl-6 {
padding-left: 40px!important;
}
.markdown-body .f6 {
font-size: 12px!important;
}
.markdown-body .lh-condensed {
line-height: 1.25!important;
}
.markdown-body .text-bold {
font-weight: 600!important;
}
.markdown-body:before {
content: "";
display: table;
}
.markdown-body:after {
clear: both;
content: "";
display: table;
}
.markdown-body>:first-child {
margin-top: 0!important;
}
.markdown-body>:last-child {
margin-bottom: 0!important;
}
.markdown-body a:not([href]) {
color: inherit;
text-decoration: none;
}
.markdown-body blockquote,
.markdown-body dl,
.markdown-body ol,
.markdown-body p,
.markdown-body pre,
.markdown-body table,
.markdown-body ul {
margin-bottom: 16px;
margin-top: 0;
}
.markdown-body hr {
background-color: #e1e4e8;
border: 0;
height: .25em;
margin: 24px 0;
padding: 0;
}
.markdown-body blockquote {
border-left: .25em solid #dfe2e5;
color: #6a737d;
padding: 0 1em;
}
.markdown-body blockquote>:first-child {
margin-top: 0;
}
.markdown-body blockquote>:last-child {
margin-bottom: 0;
}
.markdown-body kbd {
background-color: #fafbfc;
border: 1px solid #c6cbd1;
border-bottom-color: #959da5;
border-radius: 3px;
box-shadow: inset 0 -1px 0 #959da5;
color: #444d56;
display: inline-block;
font-size: 11px;
line-height: 10px;
padding: 3px 5px;
vertical-align: middle;
}
.markdown-body h1,
.markdown-body h2,
.markdown-body h3,
.markdown-body h4,
.markdown-body h5,
.markdown-body h6 {
font-weight: 600;
line-height: 1.25;
margin-bottom: 16px;
margin-top: 24px;
}
.markdown-body h1 {
font-size: 2em;
}
.markdown-body h1,
.markdown-body h2 {
border-bottom: 1px solid #eaecef;
padding-bottom: .3em;
}
.markdown-body h2 {
font-size: 1.5em;
}
.markdown-body h3 {
font-size: 1.25em;
}
.markdown-body h4 {
font-size: 1em;
}
.markdown-body h5 {
font-size: .875em;
}
.markdown-body h6 {
color: #6a737d;
font-size: .85em;
}
.markdown-body ol,
.markdown-body ul {
padding-left: 2em;
}
.markdown-body ol ol,
.markdown-body ol ul,
.markdown-body ul ol,
.markdown-body ul ul {
margin-bottom: 0;
margin-top: 0;
}
.markdown-body li {
word-wrap: break-all;
}
.markdown-body li>p {
margin-top: 16px;
}
.markdown-body li+li {
margin-top: .25em;
}
.markdown-body dl {
padding: 0;
}
.markdown-body dl dt {
font-size: 1em;
font-style: italic;
font-weight: 600;
margin-top: 16px;
padding: 0;
}
.markdown-body dl dd {
margin-bottom: 16px;
padding: 0 16px;
}
.markdown-body table {
display: block;
overflow: auto;
width: 100%;
}
.markdown-body table th {
font-weight: 600;
}
.markdown-body table td,
.markdown-body table th {
border: 1px solid #dfe2e5;
padding: 6px 13px;
}
.markdown-body table tr {
background-color: #fff;
border-top: 1px solid #c6cbd1;
}
.markdown-body table tr:nth-child(2n) {
background-color: #f6f8fa;
}
.markdown-body img {
background-color: #fff;
box-sizing: content-box;
max-width: 100%;
}
.markdown-body img[align=right] {
padding-left: 20px;
}
.markdown-body img[align=left] {
padding-right: 20px;
}
.markdown-body code {
background-color: rgba(27,31,35,.05);
border-radius: 3px;
font-size: 85%;
margin: 0;
padding: .2em .4em;
}
.markdown-body pre {
word-wrap: normal;
}
.markdown-body pre>code {
background: transparent;
border: 0;
font-size: 100%;
margin: 0;
padding: 0;
white-space: pre;
word-break: normal;
}
.markdown-body .highlight {
margin-bottom: 16px;
}
.markdown-body .highlight pre {
margin-bottom: 0;
word-break: normal;
}
.markdown-body .highlight pre,
.markdown-body pre {
background-color: #f6f8fa;
border-radius: 3px;
font-size: 85%;
line-height: 1.45;
overflow: auto;
padding: 16px;
}
.markdown-body pre code {
background-color: transparent;
border: 0;
display: inline;
line-height: inherit;
margin: 0;
max-width: auto;
overflow: visible;
padding: 0;
word-wrap: normal;
}
.markdown-body .commit-tease-sha {
color: #444d56;
display: inline-block;
font-family: SFMono-Regular,Consolas,Liberation Mono,Menlo,Courier,monospace;
font-size: 90%;
}
.markdown-body .blob-wrapper {
border-bottom-left-radius: 3px;
border-bottom-right-radius: 3px;
overflow-x: auto;
overflow-y: hidden;
}
.markdown-body .blob-wrapper-embedded {
max-height: 240px;
overflow-y: auto;
}
.markdown-body .blob-num {
-moz-user-select: none;
-ms-user-select: none;
-webkit-user-select: none;
color: rgba(27,31,35,.3);
cursor: pointer;
font-family: SFMono-Regular,Consolas,Liberation Mono,Menlo,Courier,monospace;
font-size: 12px;
line-height: 20px;
min-width: 50px;
padding-left: 10px;
padding-right: 10px;
text-align: right;
user-select: none;
vertical-align: top;
white-space: nowrap;
width: 1%;
}
.markdown-body .blob-num:hover {
color: rgba(27,31,35,.6);
}
.markdown-body .blob-num:before {
content: attr(data-line-number);
}
.markdown-body .blob-code {
line-height: 20px;
padding-left: 10px;
padding-right: 10px;
position: relative;
vertical-align: top;
}
.markdown-body .blob-code-inner {
color: #24292e;
font-family: SFMono-Regular,Consolas,Liberation Mono,Menlo,Courier,monospace;
font-size: 12px;
overflow: visible;
white-space: pre;
word-wrap: normal;
}
.markdown-body .pl-token.active,
.markdown-body .pl-token:hover {
background: #ffea7f;
cursor: pointer;
}
.markdown-body kbd {
background-color: #fafbfc;
border: 1px solid #d1d5da;
border-bottom-color: #c6cbd1;
border-radius: 3px;
box-shadow: inset 0 -1px 0 #c6cbd1;
color: #444d56;
display: inline-block;
font: 11px SFMono-Regular,Consolas,Liberation Mono,Menlo,Courier,monospace;
line-height: 10px;
padding: 3px 5px;
vertical-align: middle;
}
.markdown-body :checked+.radio-label {
border-color: #0366d6;
position: relative;
z-index: 1;
}
.markdown-body .tab-size[data-tab-size="1"] {
-moz-tab-size: 1;
tab-size: 1;
}
.markdown-body .tab-size[data-tab-size="2"] {
-moz-tab-size: 2;
tab-size: 2;
}
.markdown-body .tab-size[data-tab-size="3"] {
-moz-tab-size: 3;
tab-size: 3;
}
.markdown-body .tab-size[data-tab-size="4"] {
-moz-tab-size: 4;
tab-size: 4;
}
.markdown-body .tab-size[data-tab-size="5"] {
-moz-tab-size: 5;
tab-size: 5;
}
.markdown-body .tab-size[data-tab-size="6"] {
-moz-tab-size: 6;
tab-size: 6;
}
.markdown-body .tab-size[data-tab-size="7"] {
-moz-tab-size: 7;
tab-size: 7;
}
.markdown-body .tab-size[data-tab-size="8"] {
-moz-tab-size: 8;
tab-size: 8;
}
.markdown-body .tab-size[data-tab-size="9"] {
-moz-tab-size: 9;
tab-size: 9;
}
.markdown-body .tab-size[data-tab-size="10"] {
-moz-tab-size: 10;
tab-size: 10;
}
.markdown-body .tab-size[data-tab-size="11"] {
-moz-tab-size: 11;
tab-size: 11;
}
.markdown-body .tab-size[data-tab-size="12"] {
-moz-tab-size: 12;
tab-size: 12;
}
.markdown-body .task-list-item {
list-style-type: none;
}
.markdown-body .task-list-item+.task-list-item {
margin-top: 3px;
}
.markdown-body .task-list-item input {
margin: 0 .2em .25em -1.6em;
vertical-align: middle;
}
.markdown-body hr {
border-bottom-color: #eee;
}
.markdown-body .pl-0 {
padding-left: 0!important;
}
.markdown-body .pl-1 {
padding-left: 4px!important;
}
.markdown-body .pl-2 {
padding-left: 8px!important;
}
.markdown-body .pl-3 {
padding-left: 16px!important;
}
.markdown-body .pl-4 {
padding-left: 24px!important;
}
.markdown-body .pl-5 {
padding-left: 32px!important;
}
.markdown-body .pl-6 {
padding-left: 40px!important;
}
.markdown-body .pl-7 {
padding-left: 48px!important;
}
.markdown-body .pl-8 {
padding-left: 64px!important;
}
.markdown-body .pl-9 {
padding-left: 80px!important;
}
.markdown-body .pl-10 {
padding-left: 96px!important;
}
.markdown-body .pl-11 {
padding-left: 112px!important;
}
.markdown-body .pl-12 {
padding-left: 128px!important;
}
/*# sourceURL=webpack://./node_modules/github-markdown-css/github-markdown.css */
/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8uL25vZGVfbW9kdWxlcy9naXRodWItbWFya2Rvd24tY3NzL2dpdGh1Yi1tYXJrZG93bi5jc3MiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7RUFDRSwwQkFBMEI7RUFDMUIsMkRBQXF0RTtBQUN2dEU7O0FBRUE7RUFDRSxxQkFBcUI7RUFDckIsa0JBQWtCO0VBQ2xCLDJCQUEyQjtBQUM3Qjs7QUFFQTtFQUNFLFdBQVc7RUFDWCxjQUFjO0VBQ2Qsa0JBQWtCO0VBQ2xCLGtCQUFrQjtBQUNwQjs7QUFFQTtFQUNFLGFBQWE7QUFDZjs7QUFFQTs7Ozs7O0VBTUUsY0FBYztFQUNkLHNCQUFzQjtFQUN0QixrQkFBa0I7QUFDcEI7O0FBRUE7Ozs7OztFQU1FLHFCQUFxQjtBQUN2Qjs7QUFFQTs7Ozs7O0VBTUUsbUJBQW1CO0FBQ3JCOztBQUVBO0VBQ0UsMEJBQTBCO0VBQzFCLDhCQUE4QjtFQUM5QixjQUFjO0VBQ2QsZ0JBQWdCO0VBQ2hCLGtJQUFrSTtFQUNsSSxlQUFlO0VBQ2YsZ0JBQWdCO0VBQ2hCLHFCQUFxQjtBQUN2Qjs7QUFFQTtFQUNFLGNBQWM7QUFDaEI7O0FBRUE7O0VBRUUsY0FBYztBQUNoQjs7QUFFQTs7RUFFRSxjQUFjO0FBQ2hCOztBQUVBOztFQUVFLGNBQWM7QUFDaEI7O0FBRUE7RUFDRSxjQUFjO0FBQ2hCOztBQUVBO0VBQ0UsY0FBYztBQUNoQjs7QUFFQTs7Ozs7OztFQU9FLGNBQWM7QUFDaEI7O0FBRUE7O0VBRUUsY0FBYztBQUNoQjs7QUFFQTtFQUNFLGNBQWM7QUFDaEI7O0FBRUE7RUFDRSx5QkFBeUI7RUFDekIsY0FBYztBQUNoQjs7QUFFQTtFQUNFLHlCQUF5QjtFQUN6QixjQUFjO0FBQ2hCOztBQUVBO0VBQ0UsYUFBYTtBQUNmOztBQUVBO0VBQ0UsY0FBYztFQUNkLGdCQUFnQjtBQUNsQjs7QUFFQTtFQUNFLGNBQWM7QUFDaEI7O0FBRUE7OztFQUdFLGNBQWM7RUFDZCxnQkFBZ0I7QUFDbEI7O0FBRUE7RUFD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 */
</style>
<style>
/**
* prism.js default theme for JavaScript, CSS and HTML
* Based on dabblet (http://dabblet.com)
* @author Lea Verou
*/
code[class*="language-"],
pre[class*="language-"] {
color: black;
background: none;
text-shadow: 0 1px white;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
font-size: 1em;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}
pre[class*="language-"]::selection, pre[class*="language-"] ::selection,
code[class*="language-"]::selection, code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
}
:not(pre) > code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.token.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #9a6e3a;
/* This background color was intended by the author of this theme. */
background: hsla(0, 0%, 100%, .5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}
.token.function,
.token.class-name {
color: #DD4A68;
}
.token.regex,
.token.important,
.token.variable {
color: #e90;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
/*# sourceURL=webpack://./node_modules/prismjs/themes/prism.css */
/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8uL25vZGVfbW9kdWxlcy9wcmlzbWpzL3RoZW1lcy9wcmlzbS5jc3MiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7RUFJRTs7QUFFRjs7Q0FFQyxZQUFZO0NBQ1osZ0JBQWdCO0NBQ2hCLHdCQUF3QjtDQUN4QixzRUFBc0U7Q0FDdEUsY0FBYztDQUNkLGdCQUFnQjtDQUNoQixnQkFBZ0I7Q0FDaEIsb0JBQW9CO0NBQ3BCLGtCQUFrQjtDQUNsQixpQkFBaUI7Q0FDakIsZ0JBQWdCOztDQUVoQixnQkFBZ0I7Q0FDaEIsY0FBYztDQUNkLFdBQVc7O0NBRVgscUJBQXFCO0NBQ3JCLGtCQUFrQjtDQUNsQixpQkFBaUI7Q0FDakIsYUFBYTtBQUNkOztBQUVBOztDQUVDLGlCQUFpQjtDQUNqQixtQkFBbUI7QUFDcEI7O0FBRUE7O0NBRUMsaUJBQWlCO0NBQ2pCLG1CQUFtQjtBQUNwQjs7QUFFQTtDQUNDOztFQUVDLGlCQUFpQjtDQUNsQjtBQUNEOztBQUVBLGdCQUFnQjtBQUNoQjtDQUNDLFlBQVk7Q0FDWixjQUFjO0NBQ2QsY0FBYztBQUNmOztBQUVBOztDQUVDLG1CQUFtQjtBQUNwQjs7QUFFQSxnQkFBZ0I7QUFDaEI7Q0FDQyxhQUFhO0NBQ2IsbUJBQW1CO0NBQ25CLG1CQUFtQjtBQUNwQjs7QUFFQTs7OztDQUlDLGdCQUFnQjtBQUNqQjs7QUFFQTtDQUNDLFdBQVc7QUFDWjs7QUFFQTtDQUNDLFdBQVc7QUFDWjs7QUFFQTs7Ozs7OztDQU9DLFdBQVc7QUFDWjs7QUFFQTs7Ozs7O0NBTUMsV0FBVztBQUNaOztBQUVBOzs7OztDQUtDLGNBQWM7Q0FDZCxvRUFBb0U7Q0FDcEUsaUNBQWlDO0FBQ2xDOztBQUVBOzs7Q0FHQyxXQUFXO0FBQ1o7O0FBRUE7O0NBRUMsY0FBYztBQUNmOztBQUVBOzs7Q0FHQyxXQUFXO0FBQ1o7O0FBRUE7O0NBRUMsaUJBQWlCO0FBQ2xCO0FBQ0E7Q0FDQyxrQkFBa0I7QUFDbkI7O0FBRUE7Q0FDQyxZQUFZO0FBQ2IiLCJzb3VyY2VSb290IjoiIn0= */
</style>
<style>
</style>
<style>
.markdown-body {
font-family: -apple-system,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;
box-sizing: border-box;
min-width: 200px;
max-width: 980px;
margin: 0 auto;
padding: 45px;
}
@media not print {
.markdown-body {
padding: 45px;
}
@media (max-width: 767px) {
.markdown-body {
padding: 15px;
}
}
}
.hf-container {
color: #24292e;
line-height: 1.3;
}
.markdown-body .highlight pre,
.markdown-body pre {
white-space: pre-wrap;
}
.markdown-body table {
display: table;
}
.markdown-body img[data-align="center"] {
display: block;
margin: 0 auto;
}
.markdown-body img[data-align="right"] {
display: block;
margin: 0 0 0 auto;
}
.markdown-body li.task-list-item {
list-style-type: none;
}
.markdown-body li > [type=checkbox] {
margin: 0 0 0 -1.3em;
}
.markdown-body input[type="checkbox"] ~ p {
margin-top: 0;
display: inline-block;
}
.markdown-body ol ol,
.markdown-body ul ol {
list-style-type: decimal;
}
.markdown-body ol ol ol,
.markdown-body ol ul ol,
.markdown-body ul ol ol,
.markdown-body ul ul ol {
list-style-type: decimal;
}
</style>
<style>.markdown-body a.footnote-ref {
text-decoration: none;
}
.footnotes {
font-size: .85em;
opacity: .8;
}
.footnotes li[role="doc-endnote"] {
position: relative;
}
.footnotes .footnote-back {
position: absolute;
font-family: initial;
top: .2em;
right: 1em;
text-decoration: none;
}
.inline-math.invalid,
.multiple-math.invalid {
color: rgb(255, 105, 105);
}
.toc-container {
width: 100%;
}
.toc-container .toc-title {
font-weight: 700;
font-size: 1.2em;
margin-bottom: 0;
}
.toc-container li,
.toc-container ul,
.toc-container ul li {
list-style: none !important;
}
.toc-container > ul {
padding-left: 0;
}
.toc-container ul li span {
display : flex;
}
.toc-container ul li span a {
color: inherit;
text-decoration: none;
}
.toc-container ul li span a:hover {
color: inherit;
text-decoration: none;
}
.toc-container ul li span span.dots {
flex: 1;
height: 0.65em;
margin: 0 10px;
border-bottom: 2px dotted black;
}
/*# sourceURL=webpack://./src/muya/lib/assets/styles/exportStyle.css */
/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8uL3NyYy9tdXlhL2xpYi9hc3NldHMvc3R5bGVzL2V4cG9ydFN0eWxlLmNzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLHFCQUFxQjtBQUN2Qjs7QUFFQTtFQUNFLGdCQUFnQjtFQUNoQixXQUFXO0FBQ2I7O0FBRUE7RUFDRSxrQkFBa0I7QUFDcEI7O0FBRUE7RUFDRSxrQkFBa0I7RUFDbEIsb0JBQW9CO0VBQ3BCLFNBQVM7RUFDVCxVQUFVO0VBQ1YscUJBQXFCO0FBQ3ZCOztBQUVBOztFQUVFLHlCQUF5QjtBQUMzQjs7QUFFQTtFQUNFLFdBQVc7QUFDYjs7QUFFQTtFQUNFLGdCQUFnQjtFQUNoQixnQkFBZ0I7RUFDaEIsZ0JBQWdCO0FBQ2xCOztBQUVBOzs7RUFHRSwyQkFBMkI7QUFDN0I7O0FBRUE7RUFDRSxlQUFlO0FBQ2pCOztBQUVBO0VBQ0UsY0FBYztBQUNoQjs7QUFFQTtFQUNFLGNBQWM7RUFDZCxxQkFBcUI7QUFDdkI7QUFDQTtFQUNFLGNBQWM7RUFDZCxxQkFBcUI7QUFDdkI7O0FBRUE7RUFDRSxPQUFPO0VBQ1AsY0FBYztFQUNkLGNBQWM7RUFDZCwrQkFBK0I7QUFDakMiLCJzb3VyY2VSb290IjoiIn0= */</style>
<style>.markdown-body{}pre.front-matter{display:none!important;}</style>
<style>
span.dots {
display: none !important;
}
.toc-title {
font-size: 2rem !important;
}
.toc-h1 {
color: #4183CC !important;
font-weight: bold !important;
font-size: 1.2rem;
}
.toc-h2, .toc-h3, .toc-h4 {
color: #4183CF !important;
font-size: 1.0rem;
}
.toc-h2 {
font-size: 1.2rem;
}
.toc-h1:hover, .toc-h2:hover, .toc-h3:hover, .toc-h4:hover {
color: #4183EF !important;
text-decoration: underline !important;
}
</style>
</head>
<body>
<article class="markdown-body"><div class="toc-container"><p class="toc-title">目录</p><ul class="toc-list"><li><span><a class="toc-h1" href="#演示环境">演示环境</a><span class="dots"></span></span></li><li><span><a class="toc-h1" href="#内存模型与指针">内存模型与指针</a><span class="dots"></span></span><ul><li><span><a class="toc-h2" href="#内存模型">内存模型</a><span class="dots"></span></span></li><li><span><a class="toc-h2" href="#栈内存分配与取地址运算符">栈内存分配与取地址运算符</a><span class="dots"></span></span><ul><li><span><a class="toc-h3" href="#简单类型">简单类型</a><span class="dots"></span></span></li><li><span><a class="toc-h3" href="#结构体">结构体</a><span class="dots"></span></span></li><li><span><a class="toc-h3" href="#一维数组">一维数组</a><span class="dots"></span></span></li><li><span><a class="toc-h3" href="#二维数组">二维数组</a><span class="dots"></span></span></li></ul></li><li><span><a class="toc-h2" href="#不同类型指针对数据的访问">不同类型指针对数据的访问</a><span class="dots"></span></span></li><li><span><a class="toc-h2" href="#指针理解:交换变量值">指针理解:交换变量值</a><span class="dots"></span></span></li></ul></li><li><span><a class="toc-h1" href="#指向指针的指针(多重指针)">指向指针的指针(多重指针)</a><span class="dots"></span></span></li><li><span><a class="toc-h1" href="#void指针与指针类型转换">void指针与指针类型转换</a><span class="dots"></span></span></li><li><span><a class="toc-h1" href="#指针加减运算">指针加减运算</a><span class="dots"></span></span></li><li><span><a class="toc-h1" href="#指针应用小试">指针应用小试</a><span class="dots"></span></span><ul><li><span><a class="toc-h2" href="#判断字节序(小端存储大端存储)">判断字节序(小端存储/大端存储)</a><span class="dots"></span></span></li><li><span><a class="toc-h2" href="#qsort">qsort</a><span class="dots"></span></span></li></ul></li><li><span><a class="toc-h1" href="#数组与指针">数组与指针</a><span class="dots"></span></span><ul><li><span><a class="toc-h2" href="#一维数组-1">一维数组</a><span class="dots"></span></span></li><li><span><a class="toc-h2" href="#二维数组-1">二维数组</a><span class="dots"></span></span></li></ul></li><li><span><a class="toc-h1" href="#指针应用:动态内存">指针应用:动态内存</a><span class="dots"></span></span><ul><li><span><a class="toc-h2" href="#单个变量内存分配与释放">单个变量内存分配与释放</a><span class="dots"></span></span></li><li><span><a class="toc-h2" href="#一维数组内存分配与释放">一维数组内存分配与释放</a><span class="dots"></span></span></li><li><span><a class="toc-h2" href="#二维数组内存分配与释放">二维数组内存分配与释放</a><span class="dots"></span></span></li></ul></li><li><span><a class="toc-h1" href="#函数指针">函数指针</a><span class="dots"></span></span><ul><li><span><a class="toc-h2" href="#普通函数指针">普通函数指针</a><span class="dots"></span></span></li><li><span><a class="toc-h2" href="#类成员函数指针">类成员函数指针</a><span class="dots"></span></span></li></ul></li><li><span><a class="toc-h1" href="#智能指针">智能指针</a><span class="dots"></span></span></li><li><span><a class="toc-h1" href="#附:变量声明">附:变量声明</a><span class="dots"></span></span></li></ul></div><br>
<h1 class="atx" id="演示环境">演示环境</h1>
<p>本教程演示环境为</p>
<p><strong>Windows 10</strong> + <strong>MinGW(g++ (GCC) 12.2.0 )</strong></p>
<p>MinGW所用包为<strong>w64devkit</strong> <a href="https://github.com/skeeto/w64devkit/releases">https://github.com/skeeto/w64devkit/releases</a></p>
<p><span style="color: red;">如果能保持学习环境也是Windows 10 + MinGW最好。如果用的是Visual Studio或者其他的编译器如果遇到结果与本教程演示不相同的部分那就主要看教程中的演示主要是理解指针的操作原理。所有编译器中指针操作原理是相同的教程中在不同编译器会有不同结果的那些实验只为了理解指针而设计实际中并不这样用。</span></p>
<br>
<br>
<h1 class="atx" id="内存模型与指针">内存模型与指针</h1>
<h2 class="atx" id="内存模型">内存模型</h2>
<p>C语言中指针的作用是用来操作内存因此在正式开始指针内容学习之前需要先对程序内存模型有一个大概的了解。</p>
<p>假设一个程序运行内存为4G则简化后的内存模型如下图</p>
<p>4G内存会被分为多个区域在代码中可以直接进行数据读写的区域为<strong>栈区(stack)</strong><strong>堆区(heap)</strong></p>
<p><img alt="memory" src="img/memory.png"></p>
<p><mark>栈内存第2条特性只针对Linux+GCC以及Windows+MinGW的编译器组合。Visual&nbsp;Studio使用的分配方式与这两种都不相同。不过不影响指针行为的理解只是可能有的实验在Visual&nbsp;Studio的环境下无法复现。不过大家放心复现不现来的这些实验都是为了学习指针的特点设计的所以在实际当中不会这样用所以也不用担心实际写代码时在其他环境中无法使用。</mark></p>
<blockquote>
<p>实际内存要复杂得多,本图只是简单示意,<strong>以下所有示意图主要目的是用于理解指针的使用因此可能有些不是特别严谨不做过多深入。所有图示以Windows系统的处理方式作图其他平台会有差异但也不影响对指针的理解</strong></p>
</blockquote>
<br>
<h2 class="atx" id="栈内存分配与取地址运算符">栈内存分配与取地址运算符</h2>
<h3 class="atx" id="简单类型">简单类型</h3>
<p><a href="pointer/index.html">简单类型分配演示</a></p>
<br>
<p>通过以下代码查看<code>&amp;</code>运算符返回的地址:</p>
<pre><code class="fenced-code-block language-cpp"> <span class="token keyword">char</span> c1<span class="token punctuation">;</span>
<span class="token keyword">char</span> c2<span class="token punctuation">;</span>
<span class="token keyword">char</span> c3<span class="token punctuation">;</span>
<span class="token keyword">int</span> n1<span class="token punctuation">;</span>
<span class="token keyword">int</span> n2<span class="token punctuation">;</span>
<span class="token keyword">int</span> n3<span class="token punctuation">;</span>
<span class="token keyword">double</span> d1<span class="token punctuation">;</span>
<span class="token keyword">double</span> d2<span class="token punctuation">;</span>
<span class="token keyword">double</span> d3<span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%X\n"</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span>c1<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%X\n"</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span>c3<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%X\n"</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span>c2<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%X\n"</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span>n1<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%X\n"</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span>n2<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%X\n"</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span>n3<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%X\n"</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span>d1<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%X\n"</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span>d2<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%X\n"</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span>d3<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p><code>&amp;</code>操作符会返回对应变量第一个字节的地址,用来保存对应这些返回地址的变量称为指针:</p>
<pre><code class="fenced-code-block language-cpp"><span class="token keyword">char</span> <span class="token operator">*</span>ptr1 <span class="token operator">=</span> <span class="token operator">&amp;</span>c1<span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token operator">*</span>ptr2 <span class="token operator">=</span> <span class="token operator">&amp;</span>n1<span class="token punctuation">;</span>
<span class="token keyword">double</span> <span class="token operator">*</span>ptr3 <span class="token operator">=</span> <span class="token operator">&amp;</span>d1<span class="token punctuation">;</span></code></pre>
<p>可以通过指针操作对应地址的数据:</p>
<pre><code class="fenced-code-block language-cpp"> <span class="token operator">*</span>ptr1 <span class="token operator">=</span> <span class="token char">'A'</span><span class="token punctuation">;</span>
<span class="token operator">*</span>ptr2 <span class="token operator">=</span> <span class="token number">150</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%X: %c\n"</span><span class="token punctuation">,</span> ptr1<span class="token punctuation">,</span> c1<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%X: %d\n"</span><span class="token punctuation">,</span> ptr2<span class="token punctuation">,</span> <span class="token operator">*</span>ptr2<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h3 class="atx" id="结构体">结构体</h3>
<p>在不进行内存对齐的情况下,结构体的大小等于其中每个成员大小之和。进行内存分配时按照结构体大小进行分配 ,分配的内存从前往后分别是结构体中的每人成员</p>
<p><img alt="struct" src="img/struct.png"></p>
<p>实际当中结构体会进行内存对齐,本次课程内容只讲解内存地址与指针关系,所以内存对齐不做深入,内存对齐的原因及对齐方式参考文章:<a href="https://www.zhihu.com/question/34020134/answer/3198670376">https://www.zhihu.com/question/34020134/answer/3198670376</a></p>
<pre><code class="fenced-code-block language-cpp"> <span class="token keyword">struct</span> <span class="token class-name">S</span>
<span class="token punctuation">{</span>
<span class="token keyword">char</span> c<span class="token punctuation">;</span>
<span class="token keyword">int</span> n<span class="token punctuation">;</span>
<span class="token keyword">double</span> d<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">struct</span> <span class="token class-name">S</span> s1<span class="token punctuation">;</span>
<span class="token keyword">struct</span> <span class="token class-name">S</span> <span class="token operator">*</span>ptr <span class="token operator">=</span> <span class="token operator">&amp;</span>s1<span class="token punctuation">;</span>
ptr<span class="token operator">-&gt;</span>c <span class="token operator">=</span> <span class="token char">'A'</span><span class="token punctuation">;</span>
ptr<span class="token operator">-&gt;</span>n <span class="token operator">=</span> <span class="token number">100</span><span class="token punctuation">;</span>
ptr<span class="token operator">-&gt;</span>d <span class="token operator">=</span> <span class="token number">11.11</span><span class="token punctuation">;</span></code></pre>
<br>
<h3 class="atx" id="一维数组">一维数组</h3>
<p><img alt="array" src="img/array.png"></p>
<br>
<h3 class="atx" id="二维数组">二维数组</h3>
<p><img alt="array2" src="img/array2.png"></p>
<br>
<p>通过前面的演示可以得出以下结论:</p>
<ul>
<li>取地址运算符<code>&amp;</code>返回的都是变量对应内存第一个字节的地址(首地址)</li>
<li><strong>指针是特殊的变量,存储的内容是其他数据的首地址</strong>各种类型指针变量大小都相同为4字节或8字节由操作系统及编译器决定</li>
<li>指针是强类型的,声明时必须指明类型,因为程序需要根据类型判断需要解析多少内存数据以及如何进行解析</li>
</ul>
<br>
<h2 class="atx" id="不同类型指针对数据的访问">不同类型指针对数据的访问</h2>
<p><img alt="" src="img/pointer_parse.png"></p>
<br>
<h2 class="atx" id="指针理解:交换变量值">指针理解:交换变量值</h2>
<pre><code class="fenced-code-block language-cpp"><span class="token keyword">void</span> <span class="token function">swap1</span><span class="token punctuation">(</span><span class="token keyword">int</span> x<span class="token punctuation">,</span> <span class="token keyword">int</span> y<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">int</span> tmp <span class="token operator">=</span> x<span class="token punctuation">;</span>
x <span class="token operator">=</span> y<span class="token punctuation">;</span>
y <span class="token operator">=</span> tmp<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">void</span> <span class="token function">swap2</span><span class="token punctuation">(</span><span class="token keyword">int</span> <span class="token operator">*</span>x<span class="token punctuation">,</span> <span class="token keyword">int</span> <span class="token operator">*</span>y<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">int</span> tmp <span class="token operator">=</span> <span class="token operator">*</span>x<span class="token punctuation">;</span>
<span class="token operator">*</span>x <span class="token operator">=</span> <span class="token operator">*</span>y<span class="token punctuation">;</span>
<span class="token operator">*</span>y <span class="token operator">=</span> tmp<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">int</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">int</span> a <span class="token operator">=</span> <span class="token number">100</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> b <span class="token operator">=</span> <span class="token number">200</span><span class="token punctuation">;</span>
<span class="token comment">// swap1(a, b);</span>
<span class="token function">swap1</span><span class="token punctuation">(</span>a<span class="token punctuation">,</span> b<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"a = %d \tb = %d\n"</span><span class="token punctuation">,</span> a<span class="token punctuation">,</span> b <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>上面两个交换函数第一个是无法成功交换两个数值的,第二个可以成功交换,要理解这种现象产生的原因,需要先来看一个概念:</p>
<p><strong>栈帧</strong></p>
<p><img alt="" src="img/stack_frame_1.png"></p>
<p><strong>方式一 直接传递变量</strong></p>
<pre><code class="fenced-code-block language-cpp"><span class="token keyword">void</span> <span class="token function">swap1</span><span class="token punctuation">(</span><span class="token keyword">int</span> x<span class="token punctuation">,</span> <span class="token keyword">int</span> y<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"address in swap1: &amp;x = %X\t&amp;y = %X\n"</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span>x<span class="token punctuation">,</span> <span class="token operator">&amp;</span>y<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> tmp <span class="token operator">=</span> x<span class="token punctuation">;</span>
x <span class="token operator">=</span> y<span class="token punctuation">;</span>
y <span class="token operator">=</span> tmp<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">int</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">int</span> a <span class="token operator">=</span> <span class="token number">100</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> b <span class="token operator">=</span> <span class="token number">200</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"address in main: &amp;a = %X\t&amp;b = %X\n"</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span>a<span class="token punctuation">,</span> <span class="token operator">&amp;</span>b<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">swap1</span><span class="token punctuation">(</span>a<span class="token punctuation">,</span> b<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"a = %d \tb = %d\n"</span><span class="token punctuation">,</span> a<span class="token punctuation">,</span> b <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p><img alt="" src="img/swap_1.png"></p>
<p><strong>方式二 传递指针</strong></p>
<pre><code class="fenced-code-block language-cpp"><span class="token keyword">void</span> <span class="token function">swap2</span><span class="token punctuation">(</span><span class="token keyword">int</span> <span class="token operator">*</span>x<span class="token punctuation">,</span> <span class="token keyword">int</span> <span class="token operator">*</span>y<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"address in swap2: x = %X\t&amp;y = %X\n"</span><span class="token punctuation">,</span> x<span class="token punctuation">,</span> y<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> tmp <span class="token operator">=</span> <span class="token operator">*</span>x<span class="token punctuation">;</span>
<span class="token operator">*</span>x <span class="token operator">=</span> <span class="token operator">*</span>y<span class="token punctuation">;</span>
<span class="token operator">*</span>y <span class="token operator">=</span> tmp<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">int</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">int</span> a <span class="token operator">=</span> <span class="token number">100</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> b <span class="token operator">=</span> <span class="token number">200</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"address in main: &amp;a = %X\t&amp;b = %X\n"</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span>a<span class="token punctuation">,</span> <span class="token operator">&amp;</span>b<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">swap2</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>a<span class="token punctuation">,</span> <span class="token operator">&amp;</span>b<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"a = %d \tb = %d\n"</span><span class="token punctuation">,</span> a<span class="token punctuation">,</span> b <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p><img alt="" src="img/swap_2.png"></p>
<br>
<h1 class="atx" id="指向指针的指针(多重指针)">指向指针的指针(多重指针)</h1>
<p>指针实际上也是一个变量,因此可以再定义一个指针指向它,这样的指针叫做指向指针的指针,也叫多重指针</p>
<p><img alt="pointer_to_pointer" src="img/pointer_to_pointer.png"></p>
<p>要通过这些指针访问到<code>n1</code>操作如下</p>
<pre><code class="fenced-code-block language-cpp"><span class="token keyword">int</span> n1 <span class="token operator">=</span> <span class="token number">1234</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token operator">*</span>ptr1 <span class="token operator">=</span> <span class="token operator">&amp;</span>n1<span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token operator">*</span><span class="token operator">*</span> ptr2 <span class="token operator">=</span> <span class="token operator">&amp;</span>ptr1<span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token operator">*</span><span class="token operator">*</span><span class="token operator">*</span> ptr3 <span class="token operator">=</span> <span class="token operator">&amp;</span>ptr2<span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"ptr1: %d"</span><span class="token punctuation">,</span> <span class="token operator">*</span>ptr1<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"ptr1: %d"</span><span class="token punctuation">,</span> <span class="token operator">*</span><span class="token operator">*</span>ptr2<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"ptr1: %d"</span><span class="token punctuation">,</span> <span class="token operator">*</span><span class="token operator">*</span><span class="token operator">*</span>ptr3<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<br>
<h1 class="atx" id="void指针与指针类型转换">void指针与指针类型转换</h1>
<p>前面使用的指针类型都需要指定具体的类型,某一指针类型的变量只能存对应类型的指针,如果类型不统一会报错,需要进行类型转换才可以。</p>
<p>void类型的指针可以称为空类型、或者是未指定类型的指针可以用来存储任意类型的指针。因为没有类型所以不能进行指针加减或数据访问等操作需要转换为具体的类型再进行操作。</p>
<p>void指针只是用来存储一个首地址。</p>
<pre><code class="fenced-code-block language-cpp"> <span class="token keyword">char</span> c1<span class="token punctuation">;</span>
<span class="token keyword">int</span> n1<span class="token punctuation">;</span>
<span class="token keyword">void</span> <span class="token operator">*</span>ptr1 <span class="token operator">=</span> <span class="token operator">&amp;</span>c1<span class="token punctuation">;</span>
<span class="token keyword">void</span> <span class="token operator">*</span>ptr2 <span class="token operator">=</span> <span class="token operator">&amp;</span>n1<span class="token punctuation">;</span>
<span class="token keyword">char</span> <span class="token operator">*</span>ptr3 <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">char</span> <span class="token operator">*</span><span class="token punctuation">)</span>ptr1<span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token operator">*</span>ptr4 <span class="token operator">=</span> <span class="token generic-function"><span class="token function">reinterpret_cast</span><span class="token generic class-name"><span class="token operator">&lt;</span><span class="token keyword">int</span><span class="token operator">*</span><span class="token operator">&gt;</span></span></span><span class="token punctuation">(</span>ptr2<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token operator">*</span>ptr4 <span class="token operator">=</span> <span class="token number">100</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%d\n"</span><span class="token punctuation">,</span> n1<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<br>
<h1 class="atx" id="指针加减运算">指针加减运算</h1>
<p><code>int *p1, *p2;</code>指针为例,其加减运算意义如下,其中<code>N</code>为正整数:</p>
<table>
<thead>
<tr>
<th align="center">运算</th>
<th align="center">意义</th>
<th align="center"></th>
</tr>
</thead>
<tbody><tr>
<td align="center">p1 + N</td>
<td align="center">从p1指针的位置向后移动N个<code>int</code>的距离</td>
<td align="center">实际移动为N*4字节</td>
</tr>
<tr>
<td align="center">p1 - N</td>
<td align="center">从p1指针的位置向前移动N个<code>int</code>的距离</td>
<td align="center">实际移动为N*4字节</td>
</tr>
<tr>
<td align="center">p2 - p1</td>
<td align="center">p2与p1之间距离有多少个<code>int</code></td>
<td align="center"></td>
</tr>
</tbody></table>
<p><mark>以下实验在Linux+GCC环境上没有问题。在Windows+MinGW环境上可能会有一些意想不到的问题。在Visual&nbsp;Studio环境上应该无法复现其他编译器没有测试。所以如果所用的环境上无法达到同样的效果也没关系就看一下演示理解一下指针加减法就行在实际使用中不会写这样的代码这个代码只是为了解释指针加减设计的。这部分本来是要结合数组来演示的但是提前用这种方式来演示目的是为了说明指针运算本来就有这种特性并不依赖数组</mark></p>
<pre><code class="fenced-code-block language-cpp"> <span class="token keyword">int</span> n1 <span class="token operator">=</span> <span class="token number">100</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> n2 <span class="token operator">=</span> <span class="token number">200</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> n3 <span class="token operator">=</span> <span class="token number">300</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> n4 <span class="token operator">=</span> <span class="token number">400</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token operator">*</span>ptr <span class="token operator">=</span> <span class="token operator">&amp;</span>n4<span class="token punctuation">;</span> <span class="token comment">// Linux系统同样操作需要写为 &amp;n1</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%X\n"</span><span class="token punctuation">,</span> ptr <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%d\n"</span><span class="token punctuation">,</span> <span class="token operator">*</span><span class="token punctuation">(</span>ptr <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%d\n"</span><span class="token punctuation">,</span> <span class="token operator">*</span><span class="token punctuation">(</span>ptr <span class="token operator">+</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%d\n"</span><span class="token punctuation">,</span> <span class="token operator">*</span><span class="token punctuation">(</span>ptr <span class="token operator">+</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p><img alt="pointer_plus" src="img/pointer_plus.png"></p>
<p>可以用同样的方法测试指针减法</p>
<pre><code class="fenced-code-block language-cpp"> <span class="token keyword">int</span> <span class="token operator">*</span>ptr <span class="token operator">=</span> <span class="token operator">&amp;</span>n1<span class="token punctuation">;</span> <span class="token comment">// Linux系统同样操作需要写为 &amp;n4</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%X\n"</span><span class="token punctuation">,</span> ptr <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%d\n"</span><span class="token punctuation">,</span> <span class="token operator">*</span><span class="token punctuation">(</span>ptr <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%d\n"</span><span class="token punctuation">,</span> <span class="token operator">*</span><span class="token punctuation">(</span>ptr <span class="token operator">-</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%d\n"</span><span class="token punctuation">,</span> <span class="token operator">*</span><span class="token punctuation">(</span>ptr <span class="token operator">-</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>在上述操作中,<code>ptr+N</code><code>ptr-N</code>中的<code>N</code><code>-N</code>称为<strong>指针偏移量</strong></p>
<p>上述通过指针偏移量来访问对应地址里面的数据还可以进行如下方式的简写</p>
<pre><code class="fenced-code-block language-cpp"> <span class="token keyword">int</span> <span class="token operator">*</span>ptr <span class="token operator">=</span> <span class="token operator">&amp;</span>n4<span class="token punctuation">;</span> <span class="token comment">// Linux系统同样操作需要写为 &amp;n1</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%d\n"</span><span class="token punctuation">,</span> ptr<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// printf("%d\n", *ptr);</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%d\n"</span><span class="token punctuation">,</span> ptr<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// printf("%d\n", *(ptr + 1));</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%d\n"</span><span class="token punctuation">,</span> ptr<span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// printf("%d\n", *(ptr + 2));</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%d\n"</span><span class="token punctuation">,</span> ptr<span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// printf("%d\n", *(ptr + 3));</span></code></pre>
<p>看起来跟数组访问元素的方式一样吧,没错!不仅数组可以用下标的方式来访问元素,指针也可以用下标的方式来简写偏移量访问对应地址内的数据。</p>
<p>指针和数组之间的联系与相似之处非常多,后面再详细介绍两者的区别。</p>
<br>
<h1 class="atx" id="指针应用小试">指针应用小试</h1>
<h2 class="atx" id="判断字节序(小端存储大端存储)">判断字节序(小端存储/大端存储)</h2>
<p><img alt="byte order" src="img/byte_order.png"></p>
<p>现代计算机中大多是以小端为字节序的。</p>
<p>C++20标准库中提供了方法来判断字节序</p>
<pre><code class="fenced-code-block language-cpp"><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string">&lt;bit&gt;</span></span>
<span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string">&lt;iostream&gt;</span></span>
<span class="token keyword">int</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>std<span class="token double-colon punctuation">::</span>endian<span class="token double-colon punctuation">::</span>native <span class="token operator">==</span> std<span class="token double-colon punctuation">::</span>endian<span class="token double-colon punctuation">::</span>big<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
std<span class="token double-colon punctuation">::</span>cout <span class="token operator">&lt;&lt;</span> <span class="token string">"字节序为大端存储"</span> <span class="token operator">&lt;&lt;</span> std<span class="token double-colon punctuation">::</span>endl<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>std<span class="token double-colon punctuation">::</span>endian<span class="token double-colon punctuation">::</span>native <span class="token operator">==</span> std<span class="token double-colon punctuation">::</span>endian<span class="token double-colon punctuation">::</span>little<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
std<span class="token double-colon punctuation">::</span>cout <span class="token operator">&lt;&lt;</span> <span class="token string">"字节序为小端存储"</span> <span class="token operator">&lt;&lt;</span> std<span class="token double-colon punctuation">::</span>endl<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>但如果是C++20以前或者是用C写程序则不能使用上述方法来判断字节序需要自行写程序来判断。</p>
<p>实现原理如下:</p>
<p>一个<code>int</code>类型为4字节因此可以先定义一个<code>int</code>类型数据,再把每个字节的内容读取出来看一下就知道是以什么字节序存储的了。</p>
<pre><code class="fenced-code-block language-cpp"><span class="token keyword">int</span> n1 <span class="token operator">=</span> <span class="token number">0X415F9AC1</span><span class="token punctuation">;</span> <span class="token comment">// 用十六进制可以很清晰看出每个字节的内容</span>
<span class="token keyword">int</span> <span class="token operator">*</span>ptr1 <span class="token operator">=</span> <span class="token operator">&amp;</span>n1<span class="token punctuation">;</span> <span class="token comment">// 定义一个整形指针,这时如果直接用*ptr访问数据的话会读取指针指向位置的4个字节</span>
<span class="token comment">// 我们需要的不是一次性把4个字节都读取出来需要一次一个字节读取</span>
<span class="token comment">// 什么样的指针能读取一个字节呢? 字符类型指针: char *, 但因为char的存储范围为-128~127</span>
<span class="token comment">// 所以需要用unsigned char </span>
<span class="token keyword">unsigned</span> <span class="token keyword">char</span> <span class="token operator">*</span>ptr2 <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">unsigned</span> <span class="token keyword">char</span> <span class="token operator">*</span><span class="token punctuation">)</span>ptr1<span class="token punctuation">;</span> <span class="token comment">// 定义一个unsigned char*指针,</span>
<span class="token comment">// 让它的值跟ptr1一样</span>
<span class="token comment">// 这时用*ptr2来访问数据就只读取指针指向的第一个字节的数据了</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"第一字节:%X\n"</span><span class="token punctuation">,</span> <span class="token operator">*</span>ptr2<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 以十六进制输出,可以对比上面的数字看每个字节的内容</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"第二字节:%X\n"</span><span class="token punctuation">,</span> <span class="token operator">*</span><span class="token punctuation">(</span>ptr2 <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"第三字节:%X\n"</span><span class="token punctuation">,</span> <span class="token operator">*</span><span class="token punctuation">(</span>ptr2 <span class="token operator">+</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"第四字节:%X\n"</span><span class="token punctuation">,</span> <span class="token operator">*</span><span class="token punctuation">(</span>ptr2 <span class="token operator">+</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p><img alt="byte order" src="img/byte_order_1.png"></p>
<blockquote>
<p>练习:写一个判断字节序的函数</p>
</blockquote>
<p>再来看一个指针类型之间转换的例子,一个结构体,正常访问结构体成员的方法如下:</p>
<pre><code class="fenced-code-block language-cpp"><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">pragma</span> <span class="token expression"><span class="token function">pack</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> </span><span class="token comment">// 取消内存对齐</span></span>
<span class="token keyword">struct</span> <span class="token class-name">S</span>
<span class="token punctuation">{</span>
<span class="token keyword">char</span> a1<span class="token punctuation">;</span>
<span class="token keyword">int</span> a2<span class="token punctuation">;</span>
<span class="token keyword">double</span> a3<span class="token punctuation">;</span>
<span class="token keyword">int</span> a4<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">struct</span> <span class="token class-name">S</span> s1<span class="token punctuation">;</span>
<span class="token keyword">struct</span> <span class="token class-name">S</span> <span class="token operator">*</span>ptr1 <span class="token operator">=</span> <span class="token operator">&amp;</span>s1<span class="token punctuation">;</span>
s1<span class="token punctuation">.</span>a1 <span class="token operator">=</span> <span class="token char">'a'</span><span class="token punctuation">;</span>
s1<span class="token punctuation">.</span>a2 <span class="token operator">=</span> <span class="token number">100</span><span class="token punctuation">;</span>
ptr1<span class="token operator">-&gt;</span>a3 <span class="token operator">=</span> <span class="token number">300</span><span class="token punctuation">;</span>
ptr1<span class="token operator">-&gt;</span>a4 <span class="token operator">=</span> <span class="token number">400</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%c\n"</span><span class="token punctuation">,</span> ptr1<span class="token operator">-&gt;</span>a1<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%d\n"</span><span class="token punctuation">,</span> s1<span class="token punctuation">.</span>a4<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>但是我们注意到,<code>&amp;s1</code>返回的是结构体的首地址,也就是结构体第一个成员的首地址,即<code>&amp;s1</code><code>&amp;s1.a1</code>返回的指针虽然类型不同,但值是相同的。<code>int</code>类型大小为4字节因此对上述结构体我们可以得到下表</p>
<table>
<thead>
<tr>
<th align="center">成员</th>
<th align="center">相对结构体首地址指针偏移量(字节)</th>
</tr>
</thead>
<tbody><tr>
<td align="center">a1</td>
<td align="center">0</td>
</tr>
<tr>
<td align="center">a2</td>
<td align="center">1</td>
</tr>
<tr>
<td align="center">a3</td>
<td align="center">5</td>
</tr>
<tr>
<td align="center">a4</td>
<td align="center">13</td>
</tr>
</tbody></table>
<p>因此可以用下面的方式来访问结构体中的成员</p>
<pre><code class="fenced-code-block language-cpp"><span class="token keyword">struct</span> <span class="token class-name">S</span> <span class="token operator">*</span>ptr1 <span class="token operator">=</span> <span class="token operator">&amp;</span>s1<span class="token punctuation">;</span>
<span class="token keyword">char</span> <span class="token operator">*</span>c_ptr <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">char</span> <span class="token operator">*</span><span class="token punctuation">)</span>ptr1<span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%c\n"</span><span class="token punctuation">,</span> <span class="token operator">*</span>c_ptr<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 访问第一个成员</span>
<span class="token keyword">char</span> <span class="token operator">*</span>tmp_ptr <span class="token operator">=</span> c_ptr <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token operator">*</span>i_ptr1 <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">int</span> <span class="token operator">*</span><span class="token punctuation">)</span>tmp_ptr<span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%d\n"</span><span class="token punctuation">,</span> <span class="token operator">*</span>i_ptr1<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 访问第二个成员</span>
tmp_ptr <span class="token operator">=</span> c_ptr <span class="token operator">+</span> <span class="token number">5</span><span class="token punctuation">;</span>
<span class="token keyword">double</span> <span class="token operator">*</span>d_ptr <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">double</span> <span class="token operator">*</span><span class="token punctuation">)</span>tmp_ptr<span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%lf\n"</span><span class="token punctuation">,</span> <span class="token operator">*</span>d_ptr<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 访问第三个成员</span>
tmp_ptr <span class="token operator">=</span> c_ptr <span class="token operator">+</span> <span class="token number">13</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token operator">*</span>i_ptr2 <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">int</span> <span class="token operator">*</span><span class="token punctuation">)</span>tmp_ptr<span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%d\n"</span><span class="token punctuation">,</span> <span class="token operator">*</span>i_ptr2<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 访问第四个成员</span></code></pre>
<p><img alt="pointer to struct fields" src="img/pointer_to_struct_field.png"></p>
<br>
<h2 class="atx" id="qsort">qsort</h2>
<p>在C标准库里提供了一个快速排序的函数qsort(quick-sort),函数声明如下</p>
<pre><code class="fenced-code-block language-cpp"><span class="token keyword">void</span> <span class="token function">qsort</span><span class="token punctuation">(</span> <span class="token keyword">void</span> <span class="token operator">*</span>ptr<span class="token punctuation">,</span> size_t count<span class="token punctuation">,</span> size_t size<span class="token punctuation">,</span> <span class="token keyword">int</span> <span class="token punctuation">(</span><span class="token operator">*</span>comp<span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token keyword">const</span> <span class="token keyword">void</span><span class="token operator">*</span><span class="token punctuation">,</span> <span class="token keyword">const</span> <span class="token keyword">void</span><span class="token operator">*</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>参数</p>
<ul>
<li>ptr - 指向待排序的数组的指针</li>
<li>count - 数组的元素数目</li>
<li>size - 数组每个元素的字节大小</li>
<li>comp - 比较函数。如果首个参数小于 第二个,那么返回负整数值,如果首个参数大于 第二个,那么返回正整数值,如果两个参数等价,那么返回零。</li>
</ul>
<p>排序整形数组:</p>
<pre><code class="fenced-code-block language-cpp"><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string">&lt;stdio.h&gt;</span></span>
<span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string">&lt;stdlib.h&gt;</span></span>
<span class="token keyword">int</span> <span class="token function">cmp_int</span><span class="token punctuation">(</span><span class="token keyword">const</span> <span class="token keyword">void</span> <span class="token operator">*</span>ptr1<span class="token punctuation">,</span> <span class="token keyword">const</span> <span class="token keyword">void</span> <span class="token operator">*</span>ptr2<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">int</span> <span class="token operator">*</span>i_ptr1 <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">int</span> <span class="token operator">*</span><span class="token punctuation">)</span>ptr1<span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token operator">*</span>i_ptr2 <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">int</span> <span class="token operator">*</span><span class="token punctuation">)</span>ptr2<span class="token punctuation">;</span>
<span class="token keyword">int</span> n1 <span class="token operator">=</span> <span class="token operator">*</span>i_ptr1<span class="token punctuation">;</span>
<span class="token keyword">int</span> n2 <span class="token operator">=</span> <span class="token operator">*</span>i_ptr2<span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>n1 <span class="token operator">&lt;</span> n2<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>n1 <span class="token operator">&gt;</span> n2<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">else</span>
<span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// 以上if-else可简写为return n1 - n2; 如果要降序排列则用return n2 - n1;</span>
<span class="token comment">// 以上所有内容都可省略, 简写为 return *(int *)ptr1 - *(int *)ptr2;</span>
<span class="token punctuation">}</span>
<span class="token keyword">int</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">int</span> ar<span class="token punctuation">[</span><span class="token number">5</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token number">112</span><span class="token punctuation">,</span> <span class="token number">955</span><span class="token punctuation">,</span> <span class="token number">230</span><span class="token punctuation">,</span> <span class="token number">189</span><span class="token punctuation">,</span> <span class="token number">100</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token function">qsort</span><span class="token punctuation">(</span>ar<span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token keyword">sizeof</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span><span class="token punctuation">,</span> cmp_int<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> <span class="token number">5</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%d\t"</span><span class="token punctuation">,</span> ar<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>按指定字段对结构体数组进行排序</p>
<pre><code class="fenced-code-block language-cpp"><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string">&lt;stdio.h&gt;</span></span>
<span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string">&lt;stdlib.h&gt;</span></span>
<span class="token keyword">struct</span> <span class="token class-name">Person</span>
<span class="token punctuation">{</span>
<span class="token keyword">char</span> name<span class="token punctuation">[</span><span class="token number">20</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> age<span class="token punctuation">;</span>
<span class="token keyword">double</span> score<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token function">cmp_struct_by_age</span><span class="token punctuation">(</span><span class="token keyword">const</span> <span class="token keyword">void</span> <span class="token operator">*</span>ptr1<span class="token punctuation">,</span> <span class="token keyword">const</span> <span class="token keyword">void</span> <span class="token operator">*</span>ptr2<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">struct</span> <span class="token class-name">Person</span> <span class="token operator">*</span>s_ptr1 <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">struct</span> <span class="token class-name">Person</span> <span class="token operator">*</span><span class="token punctuation">)</span>ptr1<span class="token punctuation">;</span>
<span class="token keyword">struct</span> <span class="token class-name">Person</span> <span class="token operator">*</span>s_ptr2 <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">struct</span> <span class="token class-name">Person</span> <span class="token operator">*</span><span class="token punctuation">)</span>ptr2<span class="token punctuation">;</span>
<span class="token keyword">return</span> s_ptr1<span class="token operator">-&gt;</span>age <span class="token operator">-</span> s_ptr2<span class="token operator">-&gt;</span>age<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">int</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">struct</span> <span class="token class-name">Person</span> s_ar<span class="token punctuation">[</span><span class="token number">5</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">{</span>
<span class="token punctuation">{</span><span class="token string">"Tom"</span><span class="token punctuation">,</span> <span class="token number">66</span><span class="token punctuation">,</span> <span class="token number">90.54</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span><span class="token string">"Jerry"</span><span class="token punctuation">,</span> <span class="token number">32</span><span class="token punctuation">,</span> <span class="token number">94</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span><span class="token string">"John"</span><span class="token punctuation">,</span> <span class="token number">20</span><span class="token punctuation">,</span> <span class="token number">70.22</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span><span class="token string">"Mike"</span><span class="token punctuation">,</span> <span class="token number">40</span><span class="token punctuation">,</span> <span class="token number">60</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span><span class="token string">"Mark"</span><span class="token punctuation">,</span> <span class="token number">53</span><span class="token punctuation">,</span> <span class="token number">65</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token function">qsort</span><span class="token punctuation">(</span>s_ar<span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token keyword">sizeof</span><span class="token punctuation">(</span><span class="token keyword">struct</span> <span class="token class-name">Person</span><span class="token punctuation">)</span><span class="token punctuation">,</span> cmp_struct_by_age<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> <span class="token number">5</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"{ name: %s, \tage: %d, \tscore: %lf }\n"</span><span class="token punctuation">,</span> s_ar<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>name<span class="token punctuation">,</span> s_ar<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>age<span class="token punctuation">,</span> s_ar<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>score<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<br>
<h1 class="atx" id="数组与指针">数组与指针</h1>
<h2 class="atx" id="一维数组-1">一维数组</h2>
<p>在前面已经提过关于数组的内存分配,即按照数组所有元素大小之和一次分配对应的内存,数组里面的元素连续存储</p>
<p><img alt="" src="img/array_pointer_1.png"></p>
<p>在数组与指针的关系中,有一条重要的规则:</p>
<p><strong>在表达式中直接使用数组名时,值为数组的首地址</strong></p>
<p>这就意味着,对上图中的数组来说,<code>ar</code><code>&amp;ar[0]</code><code>&amp;a</code>表示的地址值是一样的,都是数组的首地址,但它们的指针类型却不相同,其中直接使用数组名或者是<code>&amp;ar[0]</code>返回的指针类型都是<code>int *</code>,而<code>&amp;ar</code>返回的指针类型为<code>int (*)[5]</code></p>
<p><code>&amp;ar</code>返回的指针接收方式如下:</p>
<pre><code class="fenced-code-block language-cpp"><span class="token keyword">int</span> <span class="token punctuation">(</span><span class="token operator">*</span>ptr<span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">5</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token operator">&amp;</span>ar<span class="token punctuation">;</span></code></pre>
<p>详细说明见<a href="#%E9%99%84%EF%BC%9A%E5%8F%98%E9%87%8F%E5%A3%B0%E6%98%8E">变量声明</a>,关于这个类型的指针后面再作介绍。</p>
<p>先来看一下<strong>指针对数组的基本操作</strong></p>
<pre><code class="fenced-code-block language-cpp"> <span class="token keyword">int</span> ar<span class="token punctuation">[</span><span class="token number">5</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token number">100</span><span class="token punctuation">,</span> <span class="token number">200</span><span class="token punctuation">,</span> <span class="token number">300</span><span class="token punctuation">,</span> <span class="token number">400</span><span class="token punctuation">,</span> <span class="token number">500</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token operator">*</span>ptr <span class="token operator">=</span> ar<span class="token punctuation">;</span> <span class="token comment">// 与 int *ptr = &amp;ar[0]; 效果完全一样</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token punctuation">;</span> ptr <span class="token operator">!=</span> <span class="token punctuation">(</span>ar <span class="token operator">+</span> <span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span> ptr<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token operator">*</span>ptr <span class="token operator">+=</span> <span class="token number">100</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span>ptr <span class="token operator">=</span> ar<span class="token punctuation">;</span> ptr <span class="token operator">!=</span> <span class="token punctuation">(</span>ar <span class="token operator">+</span> <span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span> ptr<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%d\t"</span><span class="token punctuation">,</span> <span class="token operator">*</span>ptr<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>直接用数组名不仅能用下标的方式访问,也可以用指针的方式访问,同时指针也可以用下标的形式访问数组内容</p>
<pre><code class="fenced-code-block language-cpp"> <span class="token keyword">int</span> ar<span class="token punctuation">[</span><span class="token number">5</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token number">100</span><span class="token punctuation">,</span> <span class="token number">200</span><span class="token punctuation">,</span> <span class="token number">300</span><span class="token punctuation">,</span> <span class="token number">400</span><span class="token punctuation">,</span> <span class="token number">500</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token operator">*</span>ptr <span class="token operator">=</span> ar<span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> <span class="token number">5</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%d\t"</span><span class="token punctuation">,</span> <span class="token operator">*</span><span class="token punctuation">(</span>ar <span class="token operator">+</span> i<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%d\t"</span><span class="token punctuation">,</span> ptr<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>可以看到数组与指针有许多相似之处,下面再来看一下数组作为函数参数的情况:</p>
<pre><code class="fenced-code-block language-cpp"><span class="token keyword">void</span> <span class="token function">print_array</span><span class="token punctuation">(</span><span class="token keyword">int</span> a<span class="token punctuation">[</span><span class="token number">5</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token keyword">int</span> n<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> n<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%d\t"</span><span class="token punctuation">,</span> a<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"\nprint_array sizeof a: %d\n"</span><span class="token punctuation">,</span> <span class="token keyword">sizeof</span><span class="token punctuation">(</span>a<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">int</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">int</span> ar<span class="token punctuation">[</span><span class="token number">5</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token number">100</span><span class="token punctuation">,</span> <span class="token number">200</span><span class="token punctuation">,</span> <span class="token number">300</span><span class="token punctuation">,</span> <span class="token number">400</span><span class="token punctuation">,</span> <span class="token number">500</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token function">print_array</span><span class="token punctuation">(</span>ar<span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"main sizeof ar: %d\n"</span><span class="token punctuation">,</span> <span class="token keyword">sizeof</span><span class="token punctuation">(</span>ar<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>通过代码观察可以发现,<code>void print_array(int a[5], int n)</code>当中的<code>int a[5]</code>里面的数字可以随便写,也可以不写,直接是<code>int a[]</code>,最终会被转为<code>int *a</code>的形式,所以数组作为函数参数传递时,都是以指针的方式传递。</p>
<p><img alt="" src="img/stack_frame.png"></p>
<p>通过前面的例子,可以总结数组名与指针的一些异同:</p>
<p><code>int ar[5];</code><code>int *ptr = ar;</code>为例</p>
<table>
<thead>
<tr>
<th align="center">数组名</th>
<th align="center">指针</th>
<th align="center">示例</th>
</tr>
</thead>
<tbody><tr>
<td align="center">可以用下标或指针偏移的方式访问</td>
<td align="center">可以用下标或指针偏移的方式访问</td>
<td align="center">*(a + 2); ptr[3];</td>
</tr>
<tr>
<td align="center">直接与数组对应内存绑定的一个变量</td>
<td align="center">一个单独变量,保存数组的首地址</td>
<td align="center">见下图</td>
</tr>
<tr>
<td align="center">包含数组大小信息</td>
<td align="center">只是一个地址,不包含数组大小信息</td>
<td align="center"></td>
</tr>
<tr>
<td align="center">自身不可改变</td>
<td align="center">可以改变指针指向的地址</td>
<td align="center">a++这种方式会报错指针则可以进行ptr++或ptr=ar2这样的操作</td>
</tr>
<tr>
<td align="center">进行指针偏移计算时直接从数组首地址开始进行计算</td>
<td align="center">进行指针偏移时需要先取出指针变量中存储的地址,再从该地址进行偏移计算</td>
<td align="center">见下图</td>
</tr>
<tr>
<td align="center">在表达式中单独将数组名作为一个变量,例如当作函数参数传递时,退化为指针</td>
<td align="center"></td>
<td align="center">int *p = ar; p = a + 3;</td>
</tr>
</tbody></table>
<p><img alt="" src="img/array_and_pointer.png"></p>
<br>
<p><strong>其他操作</strong></p>
<p>前面用指针操作数组时,都是直接将指针指向数组首地址,且指针访问范围也在数组范围内,现在来看一下其他操作。</p>
<p><img alt="" src="img/array_and_pointer_2.png"></p>
<p>通过上面的演示可以得到如下结论:</p>
<ul>
<li>如果相操作一个数组的子集可以用一个或多个指针来指向对应的位置即可重新从下标0开始访问对应那一段数据</li>
<li>指针与数组下标都可以是负数,即向前偏移,在使用数组名时千万不要把下标写为负,会访问或修改到不羽属于数组的内存数据</li>
<li>C/C++中不会对数组或指针下标进行越界检查,因此当指针越界之后可能会访问或修改到不属于当前数组的值,在使用时要特别注意</li>
</ul>
<p><strong>需要注意的是,用来操作数组元素的指针也是<code>int *</code>类型,和操作单个<code>int</code>类型变量的指针是一样的。实际上不管是数组还是单个变量,在内存上都是一样的,指针借助可以偏移的特性来访问不同位置的元素</strong></p>
<br>
<p><strong>数组类型指针</strong></p>
<p>下面讨论一个<code>&amp;ar</code>返回的指针类型<code>int (*)[5]</code>,详细说明见<a href="#%E9%99%84%EF%BC%9A%E5%8F%98%E9%87%8F%E5%A3%B0%E6%98%8E">变量声明</a></p>
<p>先来看几个简单类型的指针,<code>char *p</code>为指向字符类型的指针、<code>int *p</code>为指向<code>int</code>整型的指针、<code>struct Person *p</code>为指向结构体<code>Person</code>类型的指针,这些类型的指针如果用<code>p++</code>或者<code>p--</code>这样的操作,指针移动的字节数为一个对应的类型的大小。类比可以得出,<code>int (*ptr)[5]</code>为一个指向<code>int [5]</code>类型的指针即指向一个有5个元素的<code>int</code>型数组的指针,因此<code>ptr++</code><code>ptr--</code>移动的大小为其指向类型的大小,即<code>int [5]</code>的大小为20个字节对一维数组来说就是跳过整个数组的大小。</p>
<p>在表达式中出现时,数组名相关操作与指针对应关系如下</p>
<table>
<thead>
<tr>
<th align="center">操作方式</th>
<th align="center">返回的指针类型</th>
<th align="center">说明</th>
</tr>
</thead>
<tbody><tr>
<td align="center">ar</td>
<td align="center">int *</td>
<td align="center">返回数组首地址,也就是数组第一个元素的首地址,返回的指针类型为一个指向<code>int</code>整型的指针,可以理解为是&amp;ar[0]的简写形式</td>
</tr>
<tr>
<td align="center">&amp;ar[0]</td>
<td align="center">int *</td>
<td align="center">返回数组第一个元素的首地址,类型为指向数组元素的指针</td>
</tr>
<tr>
<td align="center">&amp;ar</td>
<td align="center">int (*)[5]</td>
<td align="center">返回数组首地址,但是一个指向整个数组类型的指针</td>
</tr>
</tbody></table>
<p>其中最常用的是直接写数组名,<code>&amp;ar</code>这种方式基本上不会用到,这里介绍这类指针目的是为二维数组与指针的操作做准备。</p>
<br>
<h2 class="atx" id="二维数组-1">二维数组</h2>
<p>要相理解二维数组指针的一些迷惑行为,我们先换个角度来理解什么是二维数组:</p>
<p><strong>二维数组实际上是一个一维数组,数组里的每个元素都是一个一维数组。</strong></p>
<p><img alt="" src="img/2darray.png"></p>
<br>
<p>类比前面的<code>char ch[5]</code>,数组里面的元素是<code>char</code>类型,因此直接使用数组名表示的是<code>char *</code>指针;<code>int ar[5]</code>,数组里面的元素是<code>int</code>类型,因此直接使用数组名表示的是<code>int *</code>指针……</p>
<p>现在的二维数组<code>int arr[3][4]</code>,当作一维数组来看,数组里面的元素类型为<code>int [4]</code>,因此直接使用数组名则为<code>int (*)[4]</code>指针</p>
<p><code>int arr[3][4]</code>,在这个声明当中,变量名为<code>arr</code>,类型为<code>int [3][4]</code>,因此<code>&amp;arr</code>返回的指针类型为</p>
<p><code>int (*)[3][4]</code></p>
<p>其中<code>arr[0]</code><code>arr[1]</code><code>arr[2]</code>则又分别表示一个一维数组,因此将其视为一维数组的数组名,在达式中直接使用一维数组数组名<code>arr[0]</code><code>arr[1]</code><code>arr[2]</code>则表示该一维数组的首地址,指针类型为<code>int *</code><code>&amp;arr[0]</code>返回的则是指向整个数组类型的指针<code>int (*)[4]</code></p>
<p>理解上述规则之后,二维数组指针操作也就同一维数组了</p>
<p><strong>二维数组作为函数参数</strong></p>
<p>最直观写法如下</p>
<pre><code class="fenced-code-block language-cpp"><span class="token keyword">void</span> <span class="token function">print_array</span><span class="token punctuation">(</span><span class="token keyword">int</span> a<span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token keyword">int</span> n<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token comment">// print code </span>
<span class="token punctuation">}</span>
<span class="token keyword">int</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">int</span> a<span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">{</span>
<span class="token punctuation">{</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span><span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token function">print_array</span><span class="token punctuation">(</span>a<span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>通过测试可以发现<code>void print_array(int a[3][4], int n)</code>这个声明中,<code>int a[3][4]</code>中第一个下标的值可以不用写,即写成<code>int a[][4]</code>,但第二个下标不能省略。</p>
<p>类比一维数组<code>int a[5]</code>作为参数传递时会被改写为<code>int *</code>指针,上述维数组可以看作一维数组,其元素类型为<code>int [4]</code>,因此作为参数传递时会被改写为一个指向<code>int [4]</code>类型的指针,即<code>int (*a)[4]</code>,实际上<code>int a[][4]</code>只是<code>int (*a)[4]</code>的一种简写形式。</p>
<h1 class="atx" id="指针应用:动态内存">指针应用:动态内存</h1>
<p>前面用指针来操作栈内存上的数据只是为了熟悉指针的规则与操作方式,指针真正发挥作用的地方是用来操作堆内存上的数据。栈内存上分配的地址可以和一个变量名绑定,通过变量名就能访问到对应内存里的数据。但是堆内存分配的地址不能绑定到变量名,只能通过指针来访问与操作,可以说如果没有指针,就没法访问与操作堆内存的数据。</p>
<p>堆内存与栈内存最大的不同在于可以动态申请与释放。</p>
<p>栈内存上的变量不能手动进行释放,只有等函数执行结束或者离开作用域之后分配的内存才会自动释放。</p>
<p>堆内存上分配的内存可以在程序运行时才确定C/C++中需要手动进行内存管理,需要的时候进行内存分配,使用结束之后需要手动释放内存。</p>
<hr>
<p><strong>C语言中动态分配与释放内存的函数</strong></p>
<pre><code class="fenced-code-block language-cpp"><span class="token keyword">void</span><span class="token operator">*</span> <span class="token function">malloc</span><span class="token punctuation">(</span>size_t size<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>按照指定大小分配内存(单位为字节),返回指针类型为<code>void *</code>,即分配内存的首地址。分配失败返回<code>NULL</code></p>
<pre><code class="fenced-code-block language-cpp"><span class="token keyword">void</span><span class="token operator">*</span> <span class="token function">calloc</span><span class="token punctuation">(</span>size_t num<span class="token punctuation">,</span> size_t size<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p><code>num</code>为需要分配的个数,<code>size</code>为每个元素的大小。分配成功会将分配的内存中所有字节初始化为0。返回指针类型为<code>void *</code>,即所分配内存的首地址。分配失败返回<code>NULL</code></p>
<pre><code class="fenced-code-block language-cpp"><span class="token keyword">void</span> <span class="token operator">*</span><span class="token function">realloc</span><span class="token punctuation">(</span><span class="token keyword">void</span> <span class="token operator">*</span>ptr<span class="token punctuation">,</span> size_t new_size<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>重新分配内存。<code>ptr</code>为已分配内存的指针,<code>new_size</code>为重新分配内存大小(单位为字节)。如果<code>ptr</code><code>NULL</code>,则效果与<code>malloc</code>相同。</p>
<p><code>realloc</code>在分配内存时按照以下步骤进行</p>
<ul>
<li>直接在<code>ptr</code>指向的区域进行内存扩张或收缩,新旧大小中的较小者范围内的区域的内容保持不变。若扩张范围,则数组新增部分的内容不会进行初始化。</li>
<li>(通常是扩张内存,<code>ptr</code>指向的区域没有足够的空闲内存来进行扩张时)分配一个大小为 <code>new_size</code> 字节的新内存块,并复制大小等于新旧大小中较小者的内存区域,然后释放旧内存块。分配失败不会释放旧内存块,返回<code>NULL</code>值。</li>
</ul>
<pre><code class="fenced-code-block language-cpp"><span class="token keyword">void</span> <span class="token function">free</span><span class="token punctuation">(</span><span class="token keyword">void</span><span class="token operator">*</span> ptr<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>释放由<code>malloc</code><code>calloc</code><code>realloc</code>分配的内存。</p>
<p><strong>C++动态内存分配</strong></p>
<p>分配内存使用<code>new</code><code>new []</code>操作符,返回对应数据类型的指针。释放内存使用<code>delete</code><code>delete []</code>操作符。</p>
<h2 class="atx" id="单个变量内存分配与释放">单个变量内存分配与释放</h2>
<pre><code class="fenced-code-block language-cpp"><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string">&lt;stdio.h&gt;</span></span>
<span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string">&lt;stdlib.h&gt;</span></span>
<span class="token keyword">int</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">char</span> <span class="token operator">*</span>cptr1 <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">char</span> <span class="token operator">*</span><span class="token punctuation">)</span><span class="token function">malloc</span><span class="token punctuation">(</span><span class="token keyword">sizeof</span><span class="token punctuation">(</span><span class="token keyword">char</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">char</span> <span class="token operator">*</span>cptr2 <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">char</span> <span class="token operator">*</span><span class="token punctuation">)</span><span class="token function">malloc</span><span class="token punctuation">(</span><span class="token keyword">sizeof</span><span class="token punctuation">(</span><span class="token keyword">char</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">char</span> <span class="token operator">*</span>cptr3 <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">char</span> <span class="token operator">*</span><span class="token punctuation">)</span><span class="token function">malloc</span><span class="token punctuation">(</span><span class="token keyword">sizeof</span><span class="token punctuation">(</span><span class="token keyword">char</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%X\n"</span><span class="token punctuation">,</span> cptr1<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%X\n"</span><span class="token punctuation">,</span> cptr2<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%X\n"</span><span class="token punctuation">,</span> cptr3<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">free</span><span class="token punctuation">(</span>cptr1<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">free</span><span class="token punctuation">(</span>cptr2<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">free</span><span class="token punctuation">(</span>cptr3<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<pre><code class="fenced-code-block language-cpp"><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string">&lt;stdio.h&gt;</span></span>
<span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string">&lt;stdlib.h&gt;</span></span>
<span class="token keyword">int</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">char</span> <span class="token operator">*</span>cptr1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token keyword">char</span><span class="token punctuation">;</span>
<span class="token keyword">char</span> <span class="token operator">*</span>cptr2 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token keyword">char</span><span class="token punctuation">;</span>
<span class="token keyword">char</span> <span class="token operator">*</span>cptr3 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token keyword">char</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%X\n"</span><span class="token punctuation">,</span> cptr1<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%X\n"</span><span class="token punctuation">,</span> cptr2<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%X\n"</span><span class="token punctuation">,</span> cptr3<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">delete</span> cptr1<span class="token punctuation">;</span>
<span class="token keyword">delete</span> cptr2<span class="token punctuation">;</span>
<span class="token keyword">delete</span> cptr3<span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>通过上面输出的信息可以看到,堆内存上分配的地址并不是连续的,这是与栈内存连续分配不同的地方。</p>
<p>上面三个内存分配示意图如下</p>
<p><img alt="" src="img/malloc_1.png"> </p>
<p><img alt="" src="img/malloc_2.png"></p>
<p>使用完成之后调用<code>free</code>或者<code>delete</code>释放对应的内存</p>
<pre><code class="fenced-code-block language-cpp"><span class="token keyword">int</span> <span class="token operator">*</span>n_ptr <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">int</span> <span class="token operator">*</span><span class="token punctuation">)</span><span class="token function">malloc</span><span class="token punctuation">(</span><span class="token keyword">sizeof</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">free</span><span class="token punctuation">(</span>n_ptr<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// C++</span>
<span class="token keyword">int</span> <span class="token operator">*</span>n_ptr <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token keyword">int</span><span class="token punctuation">;</span>
<span class="token keyword">delete</span> n_ptr<span class="token punctuation">;</span></code></pre>
<p><img alt="" src="img/malloc_int.png"></p>
<pre><code class="fenced-code-block language-cpp"><span class="token keyword">double</span> <span class="token operator">*</span>d_ptr <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">double</span> <span class="token operator">*</span><span class="token punctuation">)</span><span class="token function">malloc</span><span class="token punctuation">(</span><span class="token keyword">sizeof</span><span class="token punctuation">(</span><span class="token keyword">double</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">free</span><span class="token punctuation">(</span>d_ptr<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// C++</span>
<span class="token keyword">double</span> <span class="token operator">*</span>d_ptr <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token keyword">double</span><span class="token punctuation">;</span>
<span class="token keyword">delete</span> d_ptr<span class="token punctuation">;</span></code></pre>
<p><img alt="" src="img/malloc_double.png"></p>
<pre><code class="fenced-code-block language-cpp"><span class="token keyword">struct</span> <span class="token class-name">Person</span>
<span class="token punctuation">{</span>
<span class="token keyword">int</span> num<span class="token punctuation">;</span>
<span class="token keyword">int</span> age<span class="token punctuation">;</span>
<span class="token keyword">double</span> score<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">struct</span> <span class="token class-name">Person</span> <span class="token operator">*</span>s_ptr <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">struct</span> <span class="token class-name">Person</span><span class="token operator">*</span><span class="token punctuation">)</span><span class="token function">malloc</span><span class="token punctuation">(</span><span class="token keyword">sizeof</span><span class="token punctuation">(</span><span class="token keyword">struct</span> <span class="token class-name">Person</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">free</span><span class="token punctuation">(</span>s_ptr<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// C++</span>
<span class="token keyword">struct</span> <span class="token class-name">Person</span> <span class="token operator">*</span>s_ptr <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token keyword">struct</span> <span class="token class-name">Person</span><span class="token punctuation">;</span>
<span class="token comment">// C++中可以简写为</span>
Person <span class="token operator">*</span>s_ptr <span class="token operator">=</span> <span class="token keyword">new</span> Person<span class="token punctuation">;</span>
<span class="token keyword">delete</span> s_ptr<span class="token punctuation">;</span></code></pre>
<p>C++中引入了类的概念,所以如果要为一个类在堆内存上分配内存,则要用<code>new</code>来分配而不用C中的<code>malloc</code>,因为<code>malloc</code><code>calloc</code>这类函数虽然也能为类分配内存,但不会调用类的构造函数,<code>free</code>也不会调用类的析构函数,而<code>new</code>分配内存的同时会调用类的构造函数,<code>delete</code>释放内存时会调用类的析构函数</p>
<pre><code class="fenced-code-block language-cpp"><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string">&lt;stdio.h&gt;</span></span>
<span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string">&lt;stdlib.h&gt;</span></span>
<span class="token keyword">class</span> <span class="token class-name">Student</span>
<span class="token punctuation">{</span>
<span class="token keyword">private</span><span class="token operator">:</span>
<span class="token keyword">const</span> <span class="token keyword">char</span> <span class="token operator">*</span>name<span class="token punctuation">;</span>
<span class="token keyword">int</span> age<span class="token punctuation">;</span>
<span class="token keyword">int</span> grade<span class="token punctuation">;</span>
<span class="token keyword">public</span><span class="token operator">:</span>
<span class="token function">Student</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token function">name</span><span class="token punctuation">(</span><span class="token constant">NULL</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">age</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">grade</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"调用了Student类的无参构造函数\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">Student</span><span class="token punctuation">(</span><span class="token keyword">const</span> <span class="token keyword">char</span> <span class="token operator">*</span>name<span class="token punctuation">,</span> <span class="token keyword">int</span> age<span class="token punctuation">,</span> <span class="token keyword">int</span> grade<span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token function">name</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">age</span><span class="token punctuation">(</span>age<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">grade</span><span class="token punctuation">(</span>grade<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"调用了Student类的三参构造函数\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token operator">~</span><span class="token function">Student</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"调用了Student类的析构函数\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
Student <span class="token operator">*</span>ptr1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token function">Student</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
Student <span class="token operator">*</span>ptr2 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token function">Student</span><span class="token punctuation">(</span><span class="token string">"张三"</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
Student <span class="token operator">*</span>ptr3 <span class="token operator">=</span> <span class="token punctuation">(</span>Student<span class="token operator">*</span><span class="token punctuation">)</span><span class="token function">malloc</span><span class="token punctuation">(</span><span class="token keyword">sizeof</span><span class="token punctuation">(</span>Student<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">free</span><span class="token punctuation">(</span>ptr3<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">delete</span> ptr1<span class="token punctuation">;</span>
<span class="token keyword">delete</span> ptr2<span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<br>
<h2 class="atx" id="一维数组内存分配与释放">一维数组内存分配与释放</h2>
<p>前面使用的数组都是在栈上分配的,一般来说一个程序的栈内存空间并不大,而且栈内存上的数组分配之后大小无法修改,也无法手动释放,只有等该作用域程序结束之后才自动释放。如果数据较多或者需要动态调整数组的话就不适合存放在栈内存上。相对来说堆内存上可用空间非常多,而且数组大小可以动态调整,也可以随时根据需要进行分配和释放。</p>
<p>一维数组所用的指针与单个元素是相同的,单个变量的分配可以理解为只有一个元素的数组。</p>
<p><strong>用malloc和calloc分配数组</strong></p>
<pre><code class="fenced-code-block language-cpp"> <span class="token keyword">int</span> n <span class="token operator">=</span> <span class="token number">5</span><span class="token punctuation">;</span> <span class="token comment">// 动态数据,可以动态计算或者输入</span>
<span class="token keyword">int</span> <span class="token operator">*</span>ar_ptr <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">int</span> <span class="token operator">*</span><span class="token punctuation">)</span><span class="token function">malloc</span><span class="token punctuation">(</span><span class="token keyword">sizeof</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span> <span class="token operator">*</span> n<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> n<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%d\t"</span><span class="token punctuation">,</span> ar_ptr<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// printf("%d\t", *(ar_ptr + i)); </span>
<span class="token punctuation">}</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token operator">*</span>ar_ptr2 <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">int</span> <span class="token operator">*</span><span class="token punctuation">)</span><span class="token function">calloc</span><span class="token punctuation">(</span>n<span class="token punctuation">,</span> <span class="token keyword">sizeof</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> n<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%d\t"</span><span class="token punctuation">,</span> ar_ptr2<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// printf("%d\t", *(ar_ptr + i)); </span>
<span class="token punctuation">}</span>
<span class="token function">free</span><span class="token punctuation">(</span>ar_ptr<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">free</span><span class="token punctuation">(</span>ar_ptr2<span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre>
<p><code>malloc</code>需要计算出数组所需要的空间大小进行分配,<code>calloc</code>需要提供数组元素个数以及单个元素大小进行分配。二者的区别在于<code>malloc</code>只进行内存分配,不会初始化内存里的内容,<code>calloc</code>会将分配的内存都初始化为0。</p>
<p><strong>用new[]和delete[]来分配和释放数组内存</strong></p>
<p>相对来说C++中的数组分配方法简单许多:</p>
<pre><code class="fenced-code-block language-cpp"> <span class="token keyword">int</span> n <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span> <span class="token comment">// 数组大小,可以由运行时计算得到或者输入</span>
<span class="token keyword">int</span> <span class="token operator">*</span>ptr <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token keyword">int</span><span class="token punctuation">[</span>n<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> n<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%d\t"</span><span class="token punctuation">,</span> ptr<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// *(ptr + i)</span>
<span class="token punctuation">}</span>
<span class="token keyword">delete</span><span class="token punctuation">[</span><span class="token punctuation">]</span> ptr<span class="token punctuation">;</span></code></pre>
<p>只需要提供数组元素个数即可而且C++的分配返回的即是对应类型的指针,不需要进行指针转换。</p>
<p>上面的方法也只是分配内存,并不进行数组初始化操作,如果要进行初始化,需要改成下面的写法:</p>
<pre><code class="fenced-code-block language-cpp"><span class="token keyword">int</span> <span class="token operator">*</span>ptr <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token keyword">int</span><span class="token punctuation">[</span>n<span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 也可写成 new int[n]{};</span></code></pre>
<p>这样的写法会将分配的内存初始化为0还可以用指定的数组来初始化数组</p>
<pre><code class="fenced-code-block language-cpp"><span class="token keyword">int</span> <span class="token operator">*</span>ptr <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token keyword">int</span><span class="token punctuation">[</span>n<span class="token punctuation">]</span><span class="token punctuation">{</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>但是这种初始化方式需要保证用来初始化的数据个数不超过<code>n</code></p>
<p><img alt="" src="img/malloc_array_1.png"></p>
<p><strong>用realloc动态调整数组的大小</strong></p>
<p>在堆内存上分配的数组大小可以根据需要进行调整:</p>
<pre><code class="fenced-code-block language-cpp"> <span class="token keyword">int</span> n <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span> <span class="token comment">// 数组大小,可以由运行时计算得到或者输入</span>
<span class="token keyword">int</span> size <span class="token operator">=</span> <span class="token keyword">sizeof</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span> <span class="token operator">*</span> n<span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token operator">*</span>ptr <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">int</span> <span class="token operator">*</span><span class="token punctuation">)</span><span class="token function">malloc</span><span class="token punctuation">(</span>size<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> n<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
ptr<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> i<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"重新分配前:%X\n"</span><span class="token punctuation">,</span> ptr<span class="token punctuation">)</span><span class="token punctuation">;</span>
ptr <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">int</span> <span class="token operator">*</span><span class="token punctuation">)</span><span class="token function">realloc</span><span class="token punctuation">(</span>ptr<span class="token punctuation">,</span> size <span class="token operator">*</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"重新分配后:%X\n"</span><span class="token punctuation">,</span> ptr<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> n <span class="token operator">*</span> <span class="token number">2</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%d\t"</span><span class="token punctuation">,</span> ptr<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">free</span><span class="token punctuation">(</span>ptr<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<br>
<h2 class="atx" id="二维数组内存分配与释放">二维数组内存分配与释放</h2>
<p>二维数组在堆内存上分配方式常用的有两种,一种是按照一维数组的方式来进行分配,另外一种是借助多重指针来进行分配。</p>
<p><strong>一维数组的分配方式</strong></p>
<p>现在我们假设要分配一个<code>int</code>类型二维数组<code>p[4][5]</code></p>
<p>前面已经介绍过可以将其看作一个有4个元素的一维数组每个元素的类型为<code>int [5]</code>,即可按照一维数组的方式来进行分配</p>
<pre><code class="fenced-code-block language-cpp"> <span class="token keyword">int</span> n <span class="token operator">=</span> <span class="token number">4</span><span class="token punctuation">;</span> <span class="token comment">// 数组行数,可以由运行时计算得到或者输入</span>
<span class="token comment">// int (*ptr)[5] = (int (*)[5])malloc(sizeof(int [5]) * n);</span>
<span class="token keyword">int</span> <span class="token punctuation">(</span><span class="token operator">*</span>ptr<span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">5</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">int</span> <span class="token punctuation">(</span><span class="token operator">*</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">5</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token function">calloc</span><span class="token punctuation">(</span>n<span class="token punctuation">,</span> <span class="token keyword">sizeof</span><span class="token punctuation">(</span><span class="token keyword">int</span> <span class="token punctuation">[</span><span class="token number">5</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> n<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> j <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> j <span class="token operator">&lt;</span> <span class="token number">5</span><span class="token punctuation">;</span> j<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%d\t"</span><span class="token punctuation">,</span> ptr<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">free</span><span class="token punctuation">(</span>ptr<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>或者用C++的写法</p>
<pre><code class="fenced-code-block language-cpp"><span class="token comment">// int (*ptr)[5] = new int[n][5];</span>
<span class="token keyword">int</span> <span class="token punctuation">(</span><span class="token operator">*</span>ptr<span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">5</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token keyword">int</span><span class="token punctuation">[</span>n<span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token number">5</span><span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> n<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> j <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> j <span class="token operator">&lt;</span> <span class="token number">5</span><span class="token punctuation">;</span> j<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%d\t"</span><span class="token punctuation">,</span> ptr<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">delete</span><span class="token punctuation">[</span><span class="token punctuation">]</span> ptr<span class="token punctuation">;</span></code></pre>
<p>这种分配方法将整个数组分配在一段连续的内存上面,也是比较简单的分配方法。不足之处在于只有行是动态的,列大小必须是确定的。</p>
<blockquote>
<p>实际上对于有的编译器来说,用<code>malloc</code><code>calloc</code>来分配时列值也可以是动态的但这种方法有的编译器可能不支持。用C++的方式来分配时也不支持动态列。</p>
</blockquote>
<p>而且用这种方式分配出来的二维数组每一行的列数都是相同的。</p>
<p>现在假如我想分配一个二维数组,用来存下列数据</p>
<pre><code class="fenced-code-block language-txt">1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
1 7 21 35 35 21 7 1
1 8 28 56 70 56 28 8 1
1 9 36 84 126 126 84 36 9 1 </code></pre>
<p>当然可以分配一个<code>10×10</code>的二维数组来进行存储,但是数组会有一半的空间是闲置的,假如说我就需要根据每行的数据个数来确定这一行分配多少个元素,分配一个各行的列数不相同的数组来存储这些内容,又该如何实现呢?</p>
<p><strong>多重指针分配二维数组</strong></p>
<p>这种方式用C语言的方式稍复杂一些所以只演示一下C++当中的分配方式。</p>
<p>这种分配方式分配和释放过程都较复杂一些但是行列大小都是可变的并且可以做到不同行列数不同这里主要是用来演示指针与堆内存管理的应用实际当中也不会分配这样的数组但在C++中因为指针本身不带有数组大小信息所以需要自己记录行列数值是多少Java中数组自带length分配这种数组简直爽歪歪</p>
<p><img alt="" src="img/vl_array_2d.png"></p>
<p>C++代码如下</p>
<pre><code class="fenced-code-block language-cpp"> <span class="token keyword">int</span> row <span class="token operator">=</span> <span class="token number">5</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token operator">*</span><span class="token operator">*</span>ptr <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token keyword">int</span> <span class="token operator">*</span><span class="token punctuation">[</span>row<span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> row<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
ptr<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token keyword">int</span><span class="token punctuation">[</span>i <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> row<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> j <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> j <span class="token operator">&lt;=</span> i<span class="token punctuation">;</span> j<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%d\t"</span><span class="token punctuation">,</span> ptr<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> row<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">delete</span><span class="token punctuation">[</span><span class="token punctuation">]</span> ptr<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">delete</span><span class="token punctuation">[</span><span class="token punctuation">]</span> ptr<span class="token punctuation">;</span></code></pre>
<br>
<h1 class="atx" id="函数指针">函数指针</h1>
<p>不管是自定义的函数,例如前面定义的<code>print_array</code>还是标准库里的函数例如<code>printf</code>,其函数名也是一个内存地址,可以输出查看:</p>
<pre><code class="fenced-code-block language-cpp"> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%X\n"</span><span class="token punctuation">,</span> printf<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%X\n"</span><span class="token punctuation">,</span> print_array<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%X\n"</span><span class="token punctuation">,</span> main<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>函数经编译后会生成二进制指令,运行时会载入内存当中,存在代码区,函数名则表示这个函数入口地址。</p>
<p><img alt="" src="img/function.png"></p>
<p>函数名表示该函数的入口地址,也就是该函数编译后的二进制指令存储区域的首地址。对于函数名来说,与数组名不同,直接使用函数名或者加上取地址符返回的指针类型都是一样的,即指向该函数的指针。例如在表达式中用<code>print_array</code><code>&amp;print_array</code>是一样的。</p>
<p>如果一个指针变量里面存储的值为一个函数的入口地址,则这个指针就叫做函数指针</p>
<p><img alt="" src="img/pointer_to_function.png"></p>
<h2 class="atx" id="普通函数指针">普通函数指针</h2>
<pre><code class="fenced-code-block language-cpp"><span class="token keyword">void</span> <span class="token function">hello</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"hello world\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">void</span> <span class="token function">fun</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"另一个函数\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">int</span> <span class="token function">add</span><span class="token punctuation">(</span><span class="token keyword">int</span> a<span class="token punctuation">,</span> <span class="token keyword">int</span> b<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">return</span> a <span class="token operator">+</span> b<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">int</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">void</span> <span class="token punctuation">(</span><span class="token operator">*</span>pFun<span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
pFun <span class="token operator">=</span> hello<span class="token punctuation">;</span>
<span class="token punctuation">(</span><span class="token operator">*</span>pFun<span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
pFun <span class="token operator">=</span> fun<span class="token punctuation">;</span>
<span class="token function">pFun</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token punctuation">(</span><span class="token operator">*</span>pFun2<span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">,</span> <span class="token keyword">int</span><span class="token punctuation">)</span> <span class="token operator">=</span> add<span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%d\n"</span><span class="token punctuation">,</span> <span class="token function">pFun2</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token punctuation">(</span><span class="token operator">*</span>prt1<span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token keyword">const</span> <span class="token keyword">char</span> <span class="token operator">*</span><span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span> <span class="token operator">=</span> printf<span class="token punctuation">;</span>
<span class="token function">prt1</span><span class="token punctuation">(</span><span class="token string">"prt1\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">typedef</span> <span class="token keyword">int</span> <span class="token punctuation">(</span><span class="token operator">*</span>PRT<span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token keyword">const</span> <span class="token keyword">char</span> <span class="token operator">*</span><span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
PRT prt2 <span class="token operator">=</span> printf<span class="token punctuation">;</span>
PRT prt3 <span class="token operator">=</span> printf<span class="token punctuation">;</span>
<span class="token function">prt2</span><span class="token punctuation">(</span><span class="token string">"hello prt2\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">prt3</span><span class="token punctuation">(</span><span class="token string">"hello prt3\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>函数指针一般是当作回调函数来使用,例如前面讲过的<code>qsort</code>函数</p>
<pre><code class="fenced-code-block language-cpp"><span class="token keyword">void</span> <span class="token function">qsort</span><span class="token punctuation">(</span><span class="token keyword">void</span> <span class="token operator">*</span>ptr<span class="token punctuation">,</span> size_t count<span class="token punctuation">,</span> size_t size<span class="token punctuation">,</span> <span class="token keyword">int</span> <span class="token punctuation">(</span><span class="token operator">*</span>comp<span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token keyword">const</span> <span class="token keyword">void</span> <span class="token operator">*</span><span class="token punctuation">,</span> <span class="token keyword">const</span> <span class="token keyword">void</span> <span class="token operator">*</span><span class="token punctuation">)</span><span class="token punctuation">)</span></code></pre>
<p>第四个参数<code>int (*comp)(const void *, const void *)</code>为函数指针,其返回值为<code>int</code>类型,参数为两个<code>const void *</code>指针,这里<code>const</code>修饰表示指针指向的内容不可改变,因为比较函数不须要改变源数据的内容,所以类型加上<code>const</code></p>
<h2 class="atx" id="类成员函数指针">类成员函数指针</h2>
<p>C++类中的公开函数也可以定义函数指针。</p>
<p>类中的函数分为静态函数与成员函数</p>
<p>静态函数与普通函数一样,定义指针之后可以直接调用</p>
<pre><code class="fenced-code-block language-cpp"><span class="token keyword">class</span> <span class="token class-name">Student</span>
<span class="token punctuation">{</span>
<span class="token keyword">public</span><span class="token operator">:</span>
<span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">StaticFun</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"这是静态成员函数\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">void</span> <span class="token punctuation">(</span><span class="token operator">*</span>pFun<span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span> Student<span class="token double-colon punctuation">::</span>StaticFun<span class="token punctuation">;</span>
<span class="token function">pFun</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>成员函数的定义需要加上类名限制,而且成员函数调用必须依赖于对象实例</p>
<pre><code class="fenced-code-block language-cpp"><span class="token keyword">class</span> <span class="token class-name">Student</span>
<span class="token punctuation">{</span>
<span class="token keyword">private</span><span class="token operator">:</span>
<span class="token keyword">const</span> <span class="token keyword">char</span> <span class="token operator">*</span>name<span class="token punctuation">;</span>
<span class="token keyword">int</span> age<span class="token punctuation">;</span>
<span class="token keyword">int</span> grade<span class="token punctuation">;</span>
<span class="token keyword">void</span> <span class="token function">hello</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"hello"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span><span class="token operator">:</span>
<span class="token function">Student</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token function">name</span><span class="token punctuation">(</span><span class="token string">"张三"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">age</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">grade</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"调用了Student类的无参构造函数\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">Student</span><span class="token punctuation">(</span><span class="token keyword">const</span> <span class="token keyword">char</span> <span class="token operator">*</span>name<span class="token punctuation">,</span> <span class="token keyword">int</span> age<span class="token punctuation">,</span> <span class="token keyword">int</span> grade<span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token function">name</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">age</span><span class="token punctuation">(</span>age<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">grade</span><span class="token punctuation">(</span>grade<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"调用了Student类的三参构造函数\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token operator">~</span><span class="token function">Student</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"调用了Student类的析构函数\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">StaticFun</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"这是静态成员函数\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">virtual</span> <span class="token keyword">void</span> <span class="token function">PrintInfo</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"{ 姓名:%s, \t年龄%d, \t年级%d }\n"</span><span class="token punctuation">,</span> name<span class="token punctuation">,</span> age<span class="token punctuation">,</span> grade<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">void</span> <span class="token function">PrintInfo2</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"{ 姓名:%s, \t年龄%d, \t年级%d }\n"</span><span class="token punctuation">,</span> name<span class="token punctuation">,</span> age<span class="token punctuation">,</span> grade<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
Student <span class="token function">stu</span><span class="token punctuation">(</span><span class="token string">"张三"</span><span class="token punctuation">,</span> <span class="token number">18</span><span class="token punctuation">,</span> <span class="token number">12</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
Student <span class="token operator">*</span>s_ptr <span class="token operator">=</span> <span class="token operator">&amp;</span>stu<span class="token punctuation">;</span>
<span class="token keyword">void</span> <span class="token punctuation">(</span>Student<span class="token double-colon punctuation">::</span> <span class="token operator">*</span>pFun<span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span> Student<span class="token double-colon punctuation">::</span>PrintInfo<span class="token punctuation">;</span>
<span class="token punctuation">(</span>stu<span class="token punctuation">.</span><span class="token operator">*</span>pFun<span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">(</span>s_ptr<span class="token operator">-&gt;</span><span class="token operator">*</span>pFun<span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>具体应用比如Qt中信号与槽的连接</p>
<pre><code class="fenced-code-block language-cpp"><span class="token class-name">QObject</span><span class="token double-colon punctuation">::</span><span class="token function">connect</span><span class="token punctuation">(</span>btn<span class="token punctuation">,</span> <span class="token operator">&amp;</span>QButton<span class="token double-colon punctuation">::</span>clicked<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span>MainWindow<span class="token double-colon punctuation">::</span>onBtnClick<span class="token punctuation">)</span></code></pre>
<p>信号与槽函数都可以自定义,定义完成之后调用<code>connect</code>进行连接,这里传入的就是对象指针与成员函数指针。</p>
<p>类似于,提供了一个功能函数,需要调用类中的成员函数,但事先并不知道类中对应的成员函数会定义成什么样子,就可以采用这样的方式来传入:</p>
<pre><code class="fenced-code-block language-cpp"><span class="token keyword">class</span> <span class="token class-name">Student</span>
<span class="token punctuation">{</span>
<span class="token keyword">private</span><span class="token operator">:</span>
<span class="token keyword">const</span> <span class="token keyword">char</span> <span class="token operator">*</span>name<span class="token punctuation">;</span>
<span class="token keyword">int</span> age<span class="token punctuation">;</span>
<span class="token keyword">int</span> grade<span class="token punctuation">;</span>
<span class="token keyword">void</span> <span class="token function">hello</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"hello"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span><span class="token operator">:</span>
<span class="token function">Student</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token function">name</span><span class="token punctuation">(</span><span class="token string">"张三"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">age</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">grade</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"调用了Student类的无参构造函数\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">Student</span><span class="token punctuation">(</span><span class="token keyword">const</span> <span class="token keyword">char</span> <span class="token operator">*</span>name<span class="token punctuation">,</span> <span class="token keyword">int</span> age<span class="token punctuation">,</span> <span class="token keyword">int</span> grade<span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token function">name</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">age</span><span class="token punctuation">(</span>age<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">grade</span><span class="token punctuation">(</span>grade<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"调用了Student类的三参构造函数\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token operator">~</span><span class="token function">Student</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"调用了Student类的析构函数\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">StaticFun</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"这是静态成员函数\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">void</span> <span class="token function">PrintInfo</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"{ 姓名:%s, \t年龄%d, \t年级%d }\n"</span><span class="token punctuation">,</span> name<span class="token punctuation">,</span> age<span class="token punctuation">,</span> grade<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">void</span> <span class="token function">Hello</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"大家好,我是%s今年%d岁\n"</span><span class="token punctuation">,</span> name<span class="token punctuation">,</span> age<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token comment">// QObject::connect(btn, &amp;QButton::click, this, &amp;MainWindow::onBtnClick)</span>
<span class="token keyword">void</span> <span class="token function">DoSomething</span><span class="token punctuation">(</span>Student <span class="token operator">*</span>ptr<span class="token punctuation">,</span> <span class="token keyword">void</span> <span class="token punctuation">(</span>Student<span class="token double-colon punctuation">::</span> <span class="token operator">*</span>pFun<span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"下面请开始表演:\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">(</span>ptr<span class="token operator">-&gt;</span><span class="token operator">*</span>pFun<span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">int</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
Student <span class="token function">stu</span><span class="token punctuation">(</span><span class="token string">"张三"</span><span class="token punctuation">,</span> <span class="token number">18</span><span class="token punctuation">,</span> <span class="token number">12</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">DoSomething</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>stu<span class="token punctuation">,</span> Student<span class="token double-colon punctuation">::</span>Hello<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">DoSomething</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>stu<span class="token punctuation">,</span> Student<span class="token double-colon punctuation">::</span>PrintInfo<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h1 class="atx" id="智能指针">智能指针</h1>
<p>C/C++中,堆内存需要手动进行管理,在使用完成之后要及时释放,代码量大了之后这是一件相当繁重的工作,而且经常会忘了释放内存,会造成资源浪费,严重的还会导致程序崩溃。</p>
<p>为了简化内存管理C++提供了智能指针,可以自动进行内存释放。</p>
<p>C++中智能指针为<code>uniqu_ptr</code>(一个智能指针对象独占一个指针)和<code>shared_ptr</code>(多个智能指针对象可以共享一个指针)。其中<code>uniqu_ptr</code>对数组的支持比<code>shared_ptr</code>好一些。</p>
<p><strong>用普通方法构造智能指针</strong></p>
<pre><code class="fenced-code-block language-cpp"><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string">&lt;stdio.h&gt;</span></span>
<span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string">&lt;memory&gt;</span></span>
<span class="token keyword">class</span> <span class="token class-name">Student</span>
<span class="token punctuation">{</span>
<span class="token keyword">private</span><span class="token operator">:</span>
<span class="token keyword">const</span> <span class="token keyword">char</span> <span class="token operator">*</span>name<span class="token punctuation">;</span>
<span class="token keyword">int</span> age<span class="token punctuation">;</span>
<span class="token keyword">int</span> grade<span class="token punctuation">;</span>
<span class="token keyword">void</span> <span class="token function">hello</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"hello"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span><span class="token operator">:</span>
<span class="token function">Student</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token function">name</span><span class="token punctuation">(</span><span class="token string">"张三"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">age</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">grade</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"调用了Student类的无参构造函数\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">Student</span><span class="token punctuation">(</span><span class="token keyword">const</span> <span class="token keyword">char</span> <span class="token operator">*</span>name<span class="token punctuation">,</span> <span class="token keyword">int</span> age<span class="token punctuation">,</span> <span class="token keyword">int</span> grade<span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token function">name</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">age</span><span class="token punctuation">(</span>age<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">grade</span><span class="token punctuation">(</span>grade<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"调用了Student类的三参构造函数\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token operator">~</span><span class="token function">Student</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"调用了Student类的析构函数\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">StaticFun</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"这是静态成员函数\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">void</span> <span class="token function">PrintInfo</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"{ 姓名:%s, \t年龄%d, \t年级%d }\n"</span><span class="token punctuation">,</span> name<span class="token punctuation">,</span> age<span class="token punctuation">,</span> grade<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">void</span> <span class="token function">Hello</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"大家好,我是%s今年%d岁\n"</span><span class="token punctuation">,</span> name<span class="token punctuation">,</span> age<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
std<span class="token double-colon punctuation">::</span>unique_ptr<span class="token operator">&lt;</span><span class="token keyword">int</span><span class="token operator">&gt;</span> <span class="token function">iptr</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token keyword">int</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token operator">*</span>iptr <span class="token operator">=</span> <span class="token number">1100</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%d\n"</span><span class="token punctuation">,</span> <span class="token operator">*</span>iptr<span class="token punctuation">)</span><span class="token punctuation">;</span>
std<span class="token double-colon punctuation">::</span>shared_ptr<span class="token operator">&lt;</span>Student<span class="token operator">&gt;</span> <span class="token function">stu_ptr</span><span class="token punctuation">(</span><span class="token keyword">new</span> Student<span class="token punctuation">)</span><span class="token punctuation">;</span>
stu_ptr<span class="token operator">-&gt;</span><span class="token function">PrintInfo</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p><strong>用make_unique和make_shared构造智能指针</strong></p>
<pre><code class="fenced-code-block language-cpp"> std<span class="token double-colon punctuation">::</span>unique_ptr<span class="token operator">&lt;</span><span class="token keyword">int</span><span class="token operator">&gt;</span> iptr <span class="token operator">=</span> std<span class="token double-colon punctuation">::</span><span class="token generic-function"><span class="token function">make_unique</span><span class="token generic class-name"><span class="token operator">&lt;</span><span class="token keyword">int</span><span class="token operator">&gt;</span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token operator">*</span>iptr <span class="token operator">=</span> <span class="token number">1100</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%d\n"</span><span class="token punctuation">,</span> <span class="token operator">*</span>iptr<span class="token punctuation">)</span><span class="token punctuation">;</span>
std<span class="token double-colon punctuation">::</span>shared_ptr<span class="token operator">&lt;</span>Student<span class="token operator">&gt;</span> stu_ptr <span class="token operator">=</span> std<span class="token double-colon punctuation">::</span><span class="token generic-function"><span class="token function">make_unique</span><span class="token generic class-name"><span class="token operator">&lt;</span>Student<span class="token operator">&gt;</span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
stu_ptr<span class="token operator">-&gt;</span><span class="token function">PrintInfo</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
std<span class="token double-colon punctuation">::</span>shared_ptr<span class="token operator">&lt;</span>Student<span class="token operator">&gt;</span> stu_ptr2 <span class="token operator">=</span> std<span class="token double-colon punctuation">::</span><span class="token generic-function"><span class="token function">make_unique</span><span class="token generic class-name"><span class="token operator">&lt;</span>Student<span class="token operator">&gt;</span></span></span><span class="token punctuation">(</span><span class="token string">"李四"</span><span class="token punctuation">,</span> <span class="token number">18</span><span class="token punctuation">,</span> <span class="token number">12</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
stu_ptr2<span class="token operator">-&gt;</span><span class="token function">PrintInfo</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p><strong>数组</strong></p>
<p>对于数组,用<code>unique_ptr</code>可以用直接构造或<code>make_unique</code>构造</p>
<pre><code class="fenced-code-block language-cpp"> <span class="token keyword">int</span> count <span class="token operator">=</span> <span class="token number">5</span><span class="token punctuation">;</span>
<span class="token comment">// std::unique_ptr&lt;Student[]&gt; ar(new Student[n]);</span>
std<span class="token double-colon punctuation">::</span>unique_ptr<span class="token operator">&lt;</span>Student<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">&gt;</span> ar <span class="token operator">=</span> std<span class="token double-colon punctuation">::</span><span class="token generic-function"><span class="token function">make_unique</span><span class="token generic class-name"><span class="token operator">&lt;</span>Student<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">&gt;</span></span></span><span class="token punctuation">(</span>count<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> count<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
ar<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">PrintInfo</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p><code>shared_ptr</code>只能用直接构造</p>
<pre><code class="fenced-code-block language-cpp"> <span class="token keyword">int</span> count <span class="token operator">=</span> <span class="token number">5</span><span class="token punctuation">;</span>
std<span class="token double-colon punctuation">::</span>shared_ptr<span class="token operator">&lt;</span>Student<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">&gt;</span> <span class="token function">ar</span><span class="token punctuation">(</span><span class="token keyword">new</span> Student<span class="token punctuation">[</span>count<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> count<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
ar<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">PrintInfo</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>二维数组</p>
<pre><code class="fenced-code-block language-cpp"> <span class="token keyword">int</span> row <span class="token operator">=</span> <span class="token number">5</span><span class="token punctuation">;</span>
std<span class="token double-colon punctuation">::</span>unique_ptr<span class="token operator">&lt;</span><span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">]</span><span class="token operator">&gt;</span> ar <span class="token operator">=</span> std<span class="token double-colon punctuation">::</span><span class="token generic-function"><span class="token function">make_unique</span><span class="token generic class-name"><span class="token operator">&lt;</span><span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">]</span><span class="token operator">&gt;</span></span></span><span class="token punctuation">(</span>row<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 只有行可以是动态的</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> row<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> j <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> j <span class="token operator">&lt;</span> <span class="token number">4</span><span class="token punctuation">;</span> j<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
ar<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">[</span>j<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">(</span>i <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token punctuation">(</span>j <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> row<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> j <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> j <span class="token operator">&lt;</span> <span class="token number">4</span><span class="token punctuation">;</span> j<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%d\t"</span><span class="token punctuation">,</span> ar<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p><strong>智能指针作为函数参数</strong></p>
<p><code>shared_ptr</code>共享指针,所以可以直接用同样的<code>shared_ptr</code>当作参数</p>
<pre><code class="fenced-code-block language-cpp"><span class="token keyword">void</span> <span class="token function">print_array</span><span class="token punctuation">(</span>std<span class="token double-colon punctuation">::</span>shared_ptr<span class="token operator">&lt;</span><span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">&gt;</span> ar<span class="token punctuation">,</span> <span class="token keyword">int</span> row<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> row<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%d\t"</span><span class="token punctuation">,</span> ar<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">int</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">int</span> row <span class="token operator">=</span> <span class="token number">5</span><span class="token punctuation">;</span>
std<span class="token double-colon punctuation">::</span>shared_ptr<span class="token operator">&lt;</span><span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">&gt;</span> <span class="token function">ar</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token keyword">int</span><span class="token punctuation">[</span>row<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> row<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
ar<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> i<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">print_array</span><span class="token punctuation">(</span>ar<span class="token punctuation">,</span> row<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p><code>unique_ptr</code>独占指针,所以不能直接用相同类型当函数参数,所以需要用引用传递的方式</p>
<pre><code class="fenced-code-block language-cpp"><span class="token keyword">void</span> <span class="token function">print_array</span><span class="token punctuation">(</span>std<span class="token double-colon punctuation">::</span>unique_ptr<span class="token operator">&lt;</span><span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">&gt;</span> <span class="token operator">&amp;</span>ar<span class="token punctuation">,</span> <span class="token keyword">int</span> row<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> row<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"%d\t"</span><span class="token punctuation">,</span> ar<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">int</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">int</span> row <span class="token operator">=</span> <span class="token number">5</span><span class="token punctuation">;</span>
std<span class="token double-colon punctuation">::</span>unique_ptr<span class="token operator">&lt;</span><span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">&gt;</span> <span class="token function">ar</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token keyword">int</span><span class="token punctuation">[</span>row<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> row<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
ar<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> i<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">print_array</span><span class="token punctuation">(</span>ar<span class="token punctuation">,</span> row<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<br>
<h1 class="atx" id="附:变量声明">附:变量声明</h1>
<p>注意一个规则:</p>
<p><strong>C/C++中变量的声明由两部分组成:变量类型和变量名,除了变量名,声明中的其他部分组成变量类型</strong></p>
<p>下表为一些声明的例子:</p>
<table>
<thead>
<tr>
<th align="center">声明</th>
<th align="center">类型</th>
<th align="center">变量名</th>
<th align="center">&amp;返回的指针类型</th>
</tr>
</thead>
<tbody><tr>
<td align="center">char c1;</td>
<td align="center">char</td>
<td align="center">c1</td>
<td align="center">char *</td>
</tr>
<tr>
<td align="center">int n1;</td>
<td align="center">int</td>
<td align="center">n1</td>
<td align="center">int *</td>
</tr>
<tr>
<td align="center">double d1;</td>
<td align="center">double</td>
<td align="center">d1</td>
<td align="center">double *</td>
</tr>
<tr>
<td align="center">int *ptr;</td>
<td align="center">int *</td>
<td align="center">ptr</td>
<td align="center">int **</td>
</tr>
<tr>
<td align="center">char *ptr</td>
<td align="center">char *</td>
<td align="center">ptr</td>
<td align="center">char **</td>
</tr>
<tr>
<td align="center">int ar[5];</td>
<td align="center">int [5]</td>
<td align="center">ar</td>
<td align="center">int (*)[5]</td>
</tr>
<tr>
<td align="center">char ch[10];</td>
<td align="center">char [10]</td>
<td align="center">ch</td>
<td align="center">char (*)[10]</td>
</tr>
<tr>
<td align="center">int ar[3][4]</td>
<td align="center">int [3][4]</td>
<td align="center">ar</td>
<td align="center">int (*)[3][4]</td>
</tr>
<tr>
<td align="center">int *ar[3];</td>
<td align="center">int *[3]</td>
<td align="center">ar</td>
<td align="center"></td>
</tr>
<tr>
<td align="center">int (*ptr)[3];</td>
<td align="center">int (*)[3]</td>
<td align="center">ptr</td>
<td align="center"></td>
</tr>
<tr>
<td align="center">int fun();</td>
<td align="center">int ()</td>
<td align="center">fun</td>
<td align="center">int (*) ()</td>
</tr>
<tr>
<td align="center">void swap(int *p1, int *p2);</td>
<td align="center">void (int *, int *)</td>
<td align="center">swap</td>
<td align="center">void (*) (int *, int *)</td>
</tr>
<tr>
<td align="center">int *fun(int a1, int a2)</td>
<td align="center">int * (int , int )</td>
<td align="center">fun</td>
<td align="center">int * (*)(int , int )</td>
</tr>
<tr>
<td align="center">int (*pFun) (int a1, int a2)</td>
<td align="center">int (*) (int , int)</td>
<td align="center">pFun</td>
<td align="center"></td>
</tr>
</tbody></table>
<blockquote>
<p>需要注意区分<code>int *ptr[5]</code><code>int (*ptr)[5]</code></p>
<ul>
<li><code>int *ptr[5]</code>表示声明一个数组<code>ptr</code>,数组元素类型为<code>int *</code></li>
<li><code>int (*ptr)[5]</code>表示声明一个指针<code>ptr</code>指向的是元素个数为5的一个<code>int</code>型数组</li>
</ul>
<p><img alt="" src="img/array_pointer_2.png"></p>
</blockquote>
<hr>
<blockquote>
<p>注意区分 <code>int * fun(int a1)</code><code>int (*fun)(int a1)</code></p>
<ul>
<li><code>int * fun(int a1)</code>表示定义一个函数,函数名为<code>fun</code>,接收一个<code>int</code>类型参数,返回值为<code>int *</code>指针</li>
<li><code>int (*fun)(int a1)</code>表示定义一个指针,指向类型为一个函数,这个函数接收一个<code>int</code>型参数,返回值 也是一个<code>int</code>类型</li>
</ul>
</blockquote>
</article>
</body></html>