{"id":731,"date":"2017-11-25T14:00:29","date_gmt":"2017-11-25T22:00:29","guid":{"rendered":"http:\/\/wonghoi.humgar.com\/blog\/?p=731"},"modified":"2019-01-22T00:13:49","modified_gmt":"2019-01-22T08:13:49","slug":"understanding-the-difference-between-recognized-arrays-and-pointers","status":"publish","type":"post","link":"https:\/\/wonghoi.humgar.com\/blog\/2017\/11\/25\/understanding-the-difference-between-recognized-arrays-and-pointers\/","title":{"rendered":"Understanding the difference between recognized arrays and pointers"},"content":{"rendered":"<p style=\"text-align: center;\"><em>array\u2260\u00a0<\/em><em>pointer<\/em>:<\/p>\n<p style=\"text-align: center;\">a\u00a0<em>pointer<\/em> only contains a memory location,<br \/>\nwhile an\u00a0<em>array<\/em> already has memory allocated to hold the data.<\/p>\n<hr \/>\n<p>The confusion comes from the fact that array <em>names<\/em> are always <strong>seen<\/strong> as pointers anywhere in C, but when an array <em>name<\/em> is referred in places that the <span style=\"text-decoration: underline;\">scope<\/span>\u00a0happens know the allocated size, namely<\/p>\n<ul>\n<li><span style=\"text-decoration: underline;\">Global arrays<\/span>: everybody knows the size<\/li>\n<li><span style=\"text-decoration: underline;\">Local arrays<\/span>: <strong>only<\/strong> the instantiating function knows its size.<\/li>\n<\/ul>\n<p>, the array <em>name<\/em> itself has a superpower that pointers lack: report the underlying\u00a0<strong>allocated<\/strong> data size (NOT pointer size) using <code class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">sizeof(array)<\/code>.<\/p>\n<hr \/>\n<blockquote><p><span style=\"text-decoration: underline;\">Definition<\/span>: An\u00a0<span style=\"font-size: 1.0625rem;\">array is &#8216;<\/span><em style=\"font-size: 1.0625rem;\">recognized<\/em><span style=\"font-size: 1.0625rem;\">&#8216; if the array name is used in the <strong>scope<\/strong> that knows the underlying data size.<\/span><\/p>\n<p><span style=\"text-decoration: underline;\">Corollary<\/span>: Calling the array name with sizeof() gives the underlying allocated data size.<\/p><\/blockquote>\n<p>Examples of consequences that can be derived from the definition above:<\/p>\n<ul>\n<li>Heap allocations always return a pointer type, NOT an array <em>name<\/em>!<br \/>\nSo heap arrays are never <em>recognized<\/em>.<\/li>\n<li>VLA in C99 are considered local stack arrays, so it&#8217;s <em>recognized<\/em><\/li>\n<li><code class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">x[]<\/code> is just a cosmetic shorthand for <code class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">*x<\/code>: it doesn&#8217;t prevent any\u00a0<em>recognized<\/em> array from decaying into a pointer across boundary.<\/li>\n<li>The storage duration (static or not) does not matter. e.g.\n<ul>\n<li>Heap pointers at global level are not <em>recognized<\/em> arrays<\/li>\n<li>Static local array still loses the <em>recognition<\/em> across function boundaries<br \/>\n(unless passed carefully by data type\u00a0<code class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">T (&amp;array)[N]<\/code>).<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>Most often <em>recognized<\/em> arrays cannot be aliased without decaying into a pointer. However, we can bind a <em>recognized<\/em> array to a <em>reference to an array<\/em>, which is a completely different type. Example:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">int v[]{1,2,3,4};\r\nint (&amp;w)[4]=v;  \/\/ w is a reference to an array of size 4\r\n\r\nint* p = v;     \/\/ Decays v to a pointer. Size information lost.\r\n\/\/ int\u00a0&amp;w[4]=v; \/\/ Does not compile: this means an array of 4 references.\r\n<\/pre>\n<p>Note that the syntax requires a bracket for reference name. Omitting it will lead the compiler to misinterpret it as an array of references, which cannot* be compiled.<\/p>\n<p>This means contrary to common beliefs, you can pass a\u00a0<em>recognized<\/em> array across functions through reference, but this is rarely done because of the hassle of explicitly entering the number of elements (4 for the example above) as part of the data\u00a0<em>type<\/em>. This can still be done through templates\/constexpr, but for such inconvenience, we&#8217;re better off using <code class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">std::vector<\/code> (or <code class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">std::array<\/code> if you want near zero overhead).<\/p>\n<p>However, so far I haven&#8217;t found a way to re-recognize an array from a pointer. That means there is no way to keep a local array&#8217;s\u00a0<em>recognition<\/em> across function boundaries in C since it does not have references like C++.<\/p>\n<hr \/>\n<p>To summarize with a usage example: this post has described the entire logic needed to decide whether <code class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">sizeof(x)\/sizeof(x[0])<\/code> gives you the number of array elements, or how many times your machine pointer type is bigger than the element storage.<\/p>\n<hr \/>\n<p>* references must be bound on creation. Declaring an array of references means you want to bound references in batches. There are no mechanisms to do so as of C++14.<\/p>\n<p>&nbsp;<\/p>\n<div class=\"pvc_clear\"><\/div>\n<p id=\"pvc_stats_731\" class=\"pvc_stats all  \" data-element-id=\"731\" style=\"\"><i class=\"pvc-stats-icon medium\" aria-hidden=\"true\"><svg aria-hidden=\"true\" focusable=\"false\" data-prefix=\"far\" data-icon=\"chart-bar\" role=\"img\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 512 512\" class=\"svg-inline--fa fa-chart-bar fa-w-16 fa-2x\"><path fill=\"currentColor\" d=\"M396.8 352h22.4c6.4 0 12.8-6.4 12.8-12.8V108.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v230.4c0 6.4 6.4 12.8 12.8 12.8zm-192 0h22.4c6.4 0 12.8-6.4 12.8-12.8V140.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v198.4c0 6.4 6.4 12.8 12.8 12.8zm96 0h22.4c6.4 0 12.8-6.4 12.8-12.8V204.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v134.4c0 6.4 6.4 12.8 12.8 12.8zM496 400H48V80c0-8.84-7.16-16-16-16H16C7.16 64 0 71.16 0 80v336c0 17.67 14.33 32 32 32h464c8.84 0 16-7.16 16-16v-16c0-8.84-7.16-16-16-16zm-387.2-48h22.4c6.4 0 12.8-6.4 12.8-12.8v-70.4c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v70.4c0 6.4 6.4 12.8 12.8 12.8z\" class=\"\"><\/path><\/svg><\/i> <img loading=\"lazy\" decoding=\"async\" width=\"16\" height=\"16\" alt=\"Loading\" src=\"https:\/\/wonghoi.humgar.com\/blog\/wp-content\/plugins\/page-views-count\/ajax-loader-2x.gif\" border=0 \/><\/p>\n<div class=\"pvc_clear\"><\/div>\n","protected":false},"excerpt":{"rendered":"<p>array\u2260\u00a0pointer: a\u00a0pointer only contains a memory location, while an\u00a0array already has memory allocated to hold the data. The confusion comes from the fact that array names are always seen as pointers anywhere in C, but when an array name is &hellip; <a href=\"https:\/\/wonghoi.humgar.com\/blog\/2017\/11\/25\/understanding-the-difference-between-recognized-arrays-and-pointers\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n<div class=\"pvc_clear\"><\/div>\n<p id=\"pvc_stats_731\" class=\"pvc_stats all  \" data-element-id=\"731\" style=\"\"><i class=\"pvc-stats-icon medium\" aria-hidden=\"true\"><svg aria-hidden=\"true\" focusable=\"false\" data-prefix=\"far\" data-icon=\"chart-bar\" role=\"img\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 512 512\" class=\"svg-inline--fa fa-chart-bar fa-w-16 fa-2x\"><path fill=\"currentColor\" d=\"M396.8 352h22.4c6.4 0 12.8-6.4 12.8-12.8V108.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v230.4c0 6.4 6.4 12.8 12.8 12.8zm-192 0h22.4c6.4 0 12.8-6.4 12.8-12.8V140.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v198.4c0 6.4 6.4 12.8 12.8 12.8zm96 0h22.4c6.4 0 12.8-6.4 12.8-12.8V204.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v134.4c0 6.4 6.4 12.8 12.8 12.8zM496 400H48V80c0-8.84-7.16-16-16-16H16C7.16 64 0 71.16 0 80v336c0 17.67 14.33 32 32 32h464c8.84 0 16-7.16 16-16v-16c0-8.84-7.16-16-16-16zm-387.2-48h22.4c6.4 0 12.8-6.4 12.8-12.8v-70.4c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v70.4c0 6.4 6.4 12.8 12.8 12.8z\" class=\"\"><\/path><\/svg><\/i> <img loading=\"lazy\" decoding=\"async\" width=\"16\" height=\"16\" alt=\"Loading\" src=\"https:\/\/wonghoi.humgar.com\/blog\/wp-content\/plugins\/page-views-count\/ajax-loader-2x.gif\" border=0 \/><\/p>\n<div class=\"pvc_clear\"><\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"footnotes":""},"categories":[30,25,6,29],"tags":[],"class_list":["post-731","post","type-post","status-publish","format-standard","hentry","category-c-programming","category-cpp","category-note-to-self","category-programming"],"_links":{"self":[{"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/posts\/731","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/comments?post=731"}],"version-history":[{"count":6,"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/posts\/731\/revisions"}],"predecessor-version":[{"id":1263,"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/posts\/731\/revisions\/1263"}],"wp:attachment":[{"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/media?parent=731"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/categories?post=731"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/tags?post=731"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}