10-25-2022, 09:13 AM
Solidity Bytes and String Arrays, Concat, Allocating Memory, and Array Literals
<div>
<div class="kk-star-ratings kksr-auto kksr-align-left kksr-valign-top" data-payload="{"align":"left","id":"824257","slug":"default","valign":"top","ignore":"","reference":"auto","class":"","count":"0","readonly":"","score":"0","best":"5","gap":"5","greet":"Rate this post","legend":"0\/5 - (0 votes)","size":"24","width":"0","_legend":"{score}\/{best} - ({count} {votes})","font_factor":"1.25"}">
<div class="kksr-stars">
<div class="kksr-stars-inactive">
<div class="kksr-star" data-star="1" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
<div class="kksr-star" data-star="2" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
<div class="kksr-star" data-star="3" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
<div class="kksr-star" data-star="4" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
<div class="kksr-star" data-star="5" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
</p></div>
<div class="kksr-stars-active" style="width: 0px;">
<div class="kksr-star" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
<div class="kksr-star" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
<div class="kksr-star" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
<div class="kksr-star" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
<div class="kksr-star" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
</p></div>
</div>
<div class="kksr-legend" style="font-size: 19.2px;"> <span class="kksr-muted">Rate this post</span> </div>
</div>
<figure class="wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube"><a href="https://blog.finxter.com/solidity-bytes-and-string-arrays-concat-allocating-memory-and-array-literals/"><img src="https://blog.finxter.com/wp-content/plugins/wp-youtube-lyte/lyteCache.php?origThumbUrl=https%3A%2F%2Fi.ytimg.com%2Fvi%2FsIMtrxEmecA%2Fhqdefault.jpg" alt="YouTube Video"></a><figcaption></figcaption></figure>
<p class="has-base-background-color has-background"><img src="https://s.w.org/images/core/emoji/14.0.0/72x72/1f4a1.png" alt="?" class="wp-smiley" style="height: 1em; max-height: 1em;" /> With this article, we’ll discover a new and fascinating world of bytes and strings, as well as ways to manipulate them, allocate memory arrays, and use array literals.</p>
<p>It’s part of our long-standing tradition to make this (and other) articles a faithful companion, or a supplement to the official Solidity documentation, starting with <a rel="noreferrer noopener" href="https://docs.soliditylang.org/en/v0.8.15/types.html#bytes-and-string-as-arrays" data-type="URL" data-id="https://docs.soliditylang.org/en/v0.8.15/types.html#bytes-and-string-as-arrays" target="_blank">these</a> docs for this article’s topics.</p>
<h2>Types bytes and string</h2>
<div class="wp-block-image">
<figure class="aligncenter size-full"><img loading="lazy" width="623" height="935" src="https://blog.finxter.com/wp-content/uploads/2022/10/image-196.png" alt="" class="wp-image-824434" srcset="https://blog.finxter.com/wp-content/uploads/2022/10/image-196.png 623w, https://blog.finxter.com/wp-content/uplo...00x300.png 200w" sizes="(max-width: 623px) 100vw, 623px" /></figure>
</div>
<p>Besides the arrays we’ve <a href="https://blog.finxter.com/introduction-to-solidity-reference-types-and-arrays/" data-type="post" data-id="824146" target="_blank" rel="noreferrer noopener">already discussed</a>, there are also some unique arrays, such as <code>bytes</code> and <code>string</code> arrays. </p>
<p>We have to note that the <code>bytes</code> type is very similar to <code>bytes1[]</code>, however, the difference is that a <code>bytes</code> array is tightly packed in memory areas calldata and memory. </p>
<p>Furthermore, <code>string</code> is equal to <code>bytes</code>, but does not have a length property or support for index access.</p>
<p>Solidity doesn’t have string manipulation functions compared to other commonly used <a href="https://blog.finxter.com/21-most-profitable-programming-languages-in-2023/" data-type="post" data-id="404278" target="_blank" rel="noreferrer noopener">programming languages</a>, but this can be worked around by including third-party string libraries. </p>
<p>With vanilla <a href="https://blog.finxter.com/solidity-crash-course/" data-type="post" data-id="445146" target="_blank" rel="noreferrer noopener">Solidity</a>, we can concatenate two strings, e.g. <code>string.concat(s1, s2)</code>, and compare two strings by using their <strong>keccak-256 hash</strong>, e.g. </p>
<p class="has-base-background-color has-background"><code>keccak256(abi.encodePacked(s1)) == keccak256(abi.encodePacked(s2))</code>.</p>
<p>Regarding the preferred use (we could consider this a design pattern), the <code>bytes</code> type is better than <code>bytes1[]</code>, because <code>bytes1[]</code> is more expensive due to padding additional 31 bytes between the elements when used in memory. </p>
<p>The padding is absent in storage because of the tight packing used (<a href="https://docs.soliditylang.org/en/v0.8.15/internals/layout_in_storage.html#bytes-and-string">docs</a>).</p>
<p class="has-global-color-8-background-color has-background"><img src="https://s.w.org/images/core/emoji/14.0.0/72x72/1f44d.png" alt="?" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Note</strong>: A rule of thumb says that <code>bytes</code> should be used for arbitrary-length raw byte data and <code>string</code> for arbitrary-length string data in UTF-8.</p>
<p class="has-base-background-color has-background"><img src="https://s.w.org/images/core/emoji/14.0.0/72x72/1f4a1.png" alt="?" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Note</strong>: If our data can be stored in a variable containing a number of bytes up to 32, it is better to use one of the value types <code>bytes1 ... bytes32</code>, due to their low cost.</p>
<p>To access a byte representation of a string <code>s</code>, we could use the following construct:<code> bytes(s)[7] = 'x';</code> with regard to the string length, <code>bytes(s).length</code>, e.g.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.0 <0.9.0; /** * @title String modification * @dev Demonstrates how to modify a string represented as bytes. */
contract StringModification { string public s = "Some string"; function modifyString() public { bytes(s)[7]='Q'; }
}
</pre>
</p>
<p class="has-base-background-color has-background"><img src="https://s.w.org/images/core/emoji/14.0.0/72x72/1f4a1.png" alt="?" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Note</strong>: By using this approach, we’re accessing bytes of the UTF-8 representation, not the individual characters.</p>
<h2>Functions bytes.concat() and string.concat()</h2>
<div class="wp-block-image">
<figure class="aligncenter size-full"><img loading="lazy" width="623" height="748" src="https://blog.finxter.com/wp-content/uploads/2022/10/image-197.png" alt="" class="wp-image-824437" srcset="https://blog.finxter.com/wp-content/uploads/2022/10/image-197.png 623w, https://blog.finxter.com/wp-content/uplo...50x300.png 250w" sizes="(max-width: 623px) 100vw, 623px" /></figure>
</div>
<p>Concatenation is a synonym for joining or gluing together. </p>
<p class="has-base-background-color has-background"><img src="https://s.w.org/images/core/emoji/14.0.0/72x72/1f30d.png" alt="?" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Recommended Tutorial</strong>: <a href="https://blog.finxter.com/string-concatenation-in-solidity/" data-type="post" data-id="38223" target="_blank" rel="noreferrer noopener">String Concatenation in Solidity</a></p>
<h3>String Concatenation</h3>
<p>The function <code>string.concat()</code> enables us to concatenate any number of string values. </p>
<p>The result of using the <code>string.concat()</code> function is a single-string memory array containing the concatenated strings without any added spacing or padding. </p>
<p>If we’d like to use function parameters of other types that are not implicitly convertible to the string type, we first have to convert them to the string type.</p>
<h3>Byte Concatenation</h3>
<p>In the same manner, the <code>bytes.concat()</code> function enables us to concatenate any number of bytes or <code>bytes1 ... bytes32</code> values. </p>
<p>The function result is a single bytes memory array containing the arguments without padding. </p>
<p>If we’d like to use string parameters or other types not implicitly convertible to bytes type, we first convert them to the bytes type.</p>
<h3>Example</h3>
<p>Let’s use an example to show how a function performs both string and bytes concatenation:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="7,10" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12; contract C { string s = "Storage"; function f(bytes calldata bc, string memory sm, bytes16 b) public view { string memory concatString = string.concat(s, string(bc), "Literal", sm); assert((bytes(s).length + bc.length + 7 + bytes(sm).length) == bytes(concatString).length); bytes memory concatBytes = bytes.concat(bytes(s), bc, bc[:2], "Literal", bytes(sm), b); assert((bytes(s).length + bc.length + 2 + 7 + bytes(sm).length + b.length) == concatBytes.length); }
}
</pre>
<p>By calling <code>bytes.concat(...)</code> and <code>string.concat(...)</code> without arguments, a result is an empty array.</p>
<h2><a></a>Allocating Memory Arrays</h2>
<p>We can dynamically resize the storage arrays by adding elements via the <code>.push()</code> member function. </p>
<p>In contrast, memory arrays cannot be dynamically resized and the <code>.push()</code> member function is not available. </p>
<p>However, by using the alternative approach, we can create dynamic-length memory arrays by using the <code>new</code> operator. Just before using the <code>new</code> operator, we have to calculate the required size in advance or create a new, empty array and populate it by copying all elements.</p>
<p class="has-base-background-color has-background"><img src="https://s.w.org/images/core/emoji/14.0.0/72x72/1f4a1.png" alt="?" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Note</strong>: Following the same rule of default values, the elements of freshly allocated arrays are initialized with their default values (<a href="https://docs.soliditylang.org/en/v0.8.15/control-structures.html#default-value" target="_blank" rel="noreferrer noopener">docs</a>).</p>
<p>Here we have an example showing arrays <code>a</code> and <code>b</code>, initialized by either a constant size or a parameter-given size.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0; contract C { function f(uint len) public pure { uint[] memory a = new uint[](7); bytes memory b = new bytes(len); assert(a.length == 7); assert(b.length == len); a[6] = 8; }
}
</pre>
<h2><a></a>Array Literals</h2>
<p>Array literal is represented by a comma-separated list of any number of expressions, which are listed in square brackets, e.g. <code>[1, a, f(3)]</code>. </p>
<p>The array literal type is determined in the following way:</p>
<ol type="1">
<li>The array literal is a statically-sized memory array, and its length is the number of expressions listed in the brackets;</li>
<li>The base type of the array is determined by the type of the first expression T in the list that satisfies the condition: all other expressions must be implicitly convertible to T. If it’s not possible to find such an expression, a type error is thrown;</li>
<li>Besides the convertibility condition (point 2.), one of the expressions must be of the T type.</li>
</ol>
<p>The following example will clarify what the points above mean; the type of an array literal <code>[1, 2, 3]</code> is <code>uint8[3] memory</code>, because each of the expressions is of type <code>uint8</code>. </p>
<p>If we want to change the result to type <code>uint[3] memory</code>, we have to convert the first element to <code>uint</code>.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0; contract C { function f() public pure { g([uint(1), 2, 3]); } function g(uint[3] memory) public pure { // ... }
}
</pre>
<p>In contrast, the array literal <code>[1, -2]</code> is invalid because it doesn’t comply with point 2., stating that the first expression’s type is a target type T for implicit conversion of other expressions. </p>
<p>Since our first expression is of type <code>uint8</code>, and the second expression is of type <code>int8</code> (including the negative numbers), the second expression cannot be implicitly converted to <code>uint8</code>. </p>
<p>To avoid a type error, we can declare our array literal as <code>[int8(1), -1]</code>, forcing the first expression to be of compatible type <code>int8</code>.</p>
<p>In a more specific case of using, e.g. two-dimensional array literals, we’d step on a problem of fixed-size memory arrays that cannot be converted into each other, regardless of the compatibility of base types. </p>
<p>We can get around this problem by explicitly specifying a common base:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0; contract C { function f() public pure returns (uint24[2][4] memory) { uint24[2][4] memory x = [[uint24(0x1), 1], [0xffffff, 2], [uint24(0xff), 3], [uint24(0xffff), 4]]; // The following does not work, because some of the inner arrays are not of the right type. // uint[2][4] memory x = [[0x1, 1], [0xffffff, 2], [0xff, 3], [0xffff, 4]]; return x; }
}
</pre>
<p>We cannot assign fixed-size memory arrays to dynamically-sized memory arrays, as shown by the example:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0; // This will not compile.
contract C { function f() public { // The next line creates a type error because uint[3] memory // cannot be converted to uint[] memory. uint[] memory x = [uint(1), 3, 4]; }
}
</pre>
<p>To initialize dynamically-sized arrays, we’d have to resort to assigning the elements individually, as in the example:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0; contract C { function f() public pure { uint[] memory x = new uint[](3); x[0] = 1; x[1] = 3; x[2] = 4; }
}
</pre>
<h2><a></a>Conclusion</h2>
<p>In this article, we learned even more about reference types, in particular, <code>bytes</code> and <code>string</code> arrays and concatenation, memory array allocation, and array literals.</p>
<ol>
<li>First, we explained the uniqueness of the arrays based on bytes and string types, and also touched on some of the similarities with the <code>akin</code> types.</li>
<li>Second, we’ve peeked into how to do string concatenation, comparison, and bytes concatenation.</li>
<li>Third, we discovered the specifics of allocating memory arrays and got introduced to the new operator.</li>
<li>Fourth, we got to know array literals with rules for determining the array literal base type. We also became aware of the invalid array literals and what can be done to make them valid.</li>
</ol>
<hr class="wp-block-separator has-alpha-channel-opacity"/>
<h2>What’s Next?</h2>
<p>This tutorial is part of our extended Solidity documentation with videos and more accessible examples and explanations. You can navigate the series here (all links open in a new tab):</p>
<div class="wp-container-1 is-content-justification-center wp-block-buttons">
<div class="wp-block-button"><a class="wp-block-button__link" href="https://blog.finxter.com/introduction-to-solidity-reference-types-and-arrays/" target="_blank" rel="noreferrer noopener"><img src="https://s.w.org/images/core/emoji/14.0.0/72x72/1f448.png" alt="?" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Prev Tutorial</a></div>
<div class="wp-block-button"><a class="wp-block-button__link" href="https://blog.finxter.com/solidity-deep-dive-syllabus-video-tutorial-resources/" target="_blank" rel="noreferrer noopener"><img src="https://s.w.org/images/core/emoji/14.0.0/72x72/261d.png" alt="☝" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Syllabus</a></div>
<div class="wp-block-button"><a class="wp-block-button__link" href="https://blog.finxter.com/solidity-deep-dive-syllabus-video-tutorial-resources/" target="_blank" rel="noreferrer noopener"><img src="https://s.w.org/images/core/emoji/14.0.0/72x72/1f449.png" alt="?" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Next Tutorial</a></div>
</div>
</div>
https://www.sickgaming.net/blog/2022/10/...-literals/
<div>
<div class="kk-star-ratings kksr-auto kksr-align-left kksr-valign-top" data-payload="{"align":"left","id":"824257","slug":"default","valign":"top","ignore":"","reference":"auto","class":"","count":"0","readonly":"","score":"0","best":"5","gap":"5","greet":"Rate this post","legend":"0\/5 - (0 votes)","size":"24","width":"0","_legend":"{score}\/{best} - ({count} {votes})","font_factor":"1.25"}">
<div class="kksr-stars">
<div class="kksr-stars-inactive">
<div class="kksr-star" data-star="1" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
<div class="kksr-star" data-star="2" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
<div class="kksr-star" data-star="3" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
<div class="kksr-star" data-star="4" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
<div class="kksr-star" data-star="5" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
</p></div>
<div class="kksr-stars-active" style="width: 0px;">
<div class="kksr-star" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
<div class="kksr-star" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
<div class="kksr-star" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
<div class="kksr-star" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
<div class="kksr-star" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
</p></div>
</div>
<div class="kksr-legend" style="font-size: 19.2px;"> <span class="kksr-muted">Rate this post</span> </div>
</div>
<figure class="wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube"><a href="https://blog.finxter.com/solidity-bytes-and-string-arrays-concat-allocating-memory-and-array-literals/"><img src="https://blog.finxter.com/wp-content/plugins/wp-youtube-lyte/lyteCache.php?origThumbUrl=https%3A%2F%2Fi.ytimg.com%2Fvi%2FsIMtrxEmecA%2Fhqdefault.jpg" alt="YouTube Video"></a><figcaption></figcaption></figure>
<p class="has-base-background-color has-background"><img src="https://s.w.org/images/core/emoji/14.0.0/72x72/1f4a1.png" alt="?" class="wp-smiley" style="height: 1em; max-height: 1em;" /> With this article, we’ll discover a new and fascinating world of bytes and strings, as well as ways to manipulate them, allocate memory arrays, and use array literals.</p>
<p>It’s part of our long-standing tradition to make this (and other) articles a faithful companion, or a supplement to the official Solidity documentation, starting with <a rel="noreferrer noopener" href="https://docs.soliditylang.org/en/v0.8.15/types.html#bytes-and-string-as-arrays" data-type="URL" data-id="https://docs.soliditylang.org/en/v0.8.15/types.html#bytes-and-string-as-arrays" target="_blank">these</a> docs for this article’s topics.</p>
<h2>Types bytes and string</h2>
<div class="wp-block-image">
<figure class="aligncenter size-full"><img loading="lazy" width="623" height="935" src="https://blog.finxter.com/wp-content/uploads/2022/10/image-196.png" alt="" class="wp-image-824434" srcset="https://blog.finxter.com/wp-content/uploads/2022/10/image-196.png 623w, https://blog.finxter.com/wp-content/uplo...00x300.png 200w" sizes="(max-width: 623px) 100vw, 623px" /></figure>
</div>
<p>Besides the arrays we’ve <a href="https://blog.finxter.com/introduction-to-solidity-reference-types-and-arrays/" data-type="post" data-id="824146" target="_blank" rel="noreferrer noopener">already discussed</a>, there are also some unique arrays, such as <code>bytes</code> and <code>string</code> arrays. </p>
<p>We have to note that the <code>bytes</code> type is very similar to <code>bytes1[]</code>, however, the difference is that a <code>bytes</code> array is tightly packed in memory areas calldata and memory. </p>
<p>Furthermore, <code>string</code> is equal to <code>bytes</code>, but does not have a length property or support for index access.</p>
<p>Solidity doesn’t have string manipulation functions compared to other commonly used <a href="https://blog.finxter.com/21-most-profitable-programming-languages-in-2023/" data-type="post" data-id="404278" target="_blank" rel="noreferrer noopener">programming languages</a>, but this can be worked around by including third-party string libraries. </p>
<p>With vanilla <a href="https://blog.finxter.com/solidity-crash-course/" data-type="post" data-id="445146" target="_blank" rel="noreferrer noopener">Solidity</a>, we can concatenate two strings, e.g. <code>string.concat(s1, s2)</code>, and compare two strings by using their <strong>keccak-256 hash</strong>, e.g. </p>
<p class="has-base-background-color has-background"><code>keccak256(abi.encodePacked(s1)) == keccak256(abi.encodePacked(s2))</code>.</p>
<p>Regarding the preferred use (we could consider this a design pattern), the <code>bytes</code> type is better than <code>bytes1[]</code>, because <code>bytes1[]</code> is more expensive due to padding additional 31 bytes between the elements when used in memory. </p>
<p>The padding is absent in storage because of the tight packing used (<a href="https://docs.soliditylang.org/en/v0.8.15/internals/layout_in_storage.html#bytes-and-string">docs</a>).</p>
<p class="has-global-color-8-background-color has-background"><img src="https://s.w.org/images/core/emoji/14.0.0/72x72/1f44d.png" alt="?" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Note</strong>: A rule of thumb says that <code>bytes</code> should be used for arbitrary-length raw byte data and <code>string</code> for arbitrary-length string data in UTF-8.</p>
<p class="has-base-background-color has-background"><img src="https://s.w.org/images/core/emoji/14.0.0/72x72/1f4a1.png" alt="?" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Note</strong>: If our data can be stored in a variable containing a number of bytes up to 32, it is better to use one of the value types <code>bytes1 ... bytes32</code>, due to their low cost.</p>
<p>To access a byte representation of a string <code>s</code>, we could use the following construct:<code> bytes(s)[7] = 'x';</code> with regard to the string length, <code>bytes(s).length</code>, e.g.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.0 <0.9.0; /** * @title String modification * @dev Demonstrates how to modify a string represented as bytes. */
contract StringModification { string public s = "Some string"; function modifyString() public { bytes(s)[7]='Q'; }
}
</pre>
</p>
<p class="has-base-background-color has-background"><img src="https://s.w.org/images/core/emoji/14.0.0/72x72/1f4a1.png" alt="?" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Note</strong>: By using this approach, we’re accessing bytes of the UTF-8 representation, not the individual characters.</p>
<h2>Functions bytes.concat() and string.concat()</h2>
<div class="wp-block-image">
<figure class="aligncenter size-full"><img loading="lazy" width="623" height="748" src="https://blog.finxter.com/wp-content/uploads/2022/10/image-197.png" alt="" class="wp-image-824437" srcset="https://blog.finxter.com/wp-content/uploads/2022/10/image-197.png 623w, https://blog.finxter.com/wp-content/uplo...50x300.png 250w" sizes="(max-width: 623px) 100vw, 623px" /></figure>
</div>
<p>Concatenation is a synonym for joining or gluing together. </p>
<p class="has-base-background-color has-background"><img src="https://s.w.org/images/core/emoji/14.0.0/72x72/1f30d.png" alt="?" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Recommended Tutorial</strong>: <a href="https://blog.finxter.com/string-concatenation-in-solidity/" data-type="post" data-id="38223" target="_blank" rel="noreferrer noopener">String Concatenation in Solidity</a></p>
<h3>String Concatenation</h3>
<p>The function <code>string.concat()</code> enables us to concatenate any number of string values. </p>
<p>The result of using the <code>string.concat()</code> function is a single-string memory array containing the concatenated strings without any added spacing or padding. </p>
<p>If we’d like to use function parameters of other types that are not implicitly convertible to the string type, we first have to convert them to the string type.</p>
<h3>Byte Concatenation</h3>
<p>In the same manner, the <code>bytes.concat()</code> function enables us to concatenate any number of bytes or <code>bytes1 ... bytes32</code> values. </p>
<p>The function result is a single bytes memory array containing the arguments without padding. </p>
<p>If we’d like to use string parameters or other types not implicitly convertible to bytes type, we first convert them to the bytes type.</p>
<h3>Example</h3>
<p>Let’s use an example to show how a function performs both string and bytes concatenation:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="7,10" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12; contract C { string s = "Storage"; function f(bytes calldata bc, string memory sm, bytes16 b) public view { string memory concatString = string.concat(s, string(bc), "Literal", sm); assert((bytes(s).length + bc.length + 7 + bytes(sm).length) == bytes(concatString).length); bytes memory concatBytes = bytes.concat(bytes(s), bc, bc[:2], "Literal", bytes(sm), b); assert((bytes(s).length + bc.length + 2 + 7 + bytes(sm).length + b.length) == concatBytes.length); }
}
</pre>
<p>By calling <code>bytes.concat(...)</code> and <code>string.concat(...)</code> without arguments, a result is an empty array.</p>
<h2><a></a>Allocating Memory Arrays</h2>
<p>We can dynamically resize the storage arrays by adding elements via the <code>.push()</code> member function. </p>
<p>In contrast, memory arrays cannot be dynamically resized and the <code>.push()</code> member function is not available. </p>
<p>However, by using the alternative approach, we can create dynamic-length memory arrays by using the <code>new</code> operator. Just before using the <code>new</code> operator, we have to calculate the required size in advance or create a new, empty array and populate it by copying all elements.</p>
<p class="has-base-background-color has-background"><img src="https://s.w.org/images/core/emoji/14.0.0/72x72/1f4a1.png" alt="?" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Note</strong>: Following the same rule of default values, the elements of freshly allocated arrays are initialized with their default values (<a href="https://docs.soliditylang.org/en/v0.8.15/control-structures.html#default-value" target="_blank" rel="noreferrer noopener">docs</a>).</p>
<p>Here we have an example showing arrays <code>a</code> and <code>b</code>, initialized by either a constant size or a parameter-given size.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0; contract C { function f(uint len) public pure { uint[] memory a = new uint[](7); bytes memory b = new bytes(len); assert(a.length == 7); assert(b.length == len); a[6] = 8; }
}
</pre>
<h2><a></a>Array Literals</h2>
<p>Array literal is represented by a comma-separated list of any number of expressions, which are listed in square brackets, e.g. <code>[1, a, f(3)]</code>. </p>
<p>The array literal type is determined in the following way:</p>
<ol type="1">
<li>The array literal is a statically-sized memory array, and its length is the number of expressions listed in the brackets;</li>
<li>The base type of the array is determined by the type of the first expression T in the list that satisfies the condition: all other expressions must be implicitly convertible to T. If it’s not possible to find such an expression, a type error is thrown;</li>
<li>Besides the convertibility condition (point 2.), one of the expressions must be of the T type.</li>
</ol>
<p>The following example will clarify what the points above mean; the type of an array literal <code>[1, 2, 3]</code> is <code>uint8[3] memory</code>, because each of the expressions is of type <code>uint8</code>. </p>
<p>If we want to change the result to type <code>uint[3] memory</code>, we have to convert the first element to <code>uint</code>.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0; contract C { function f() public pure { g([uint(1), 2, 3]); } function g(uint[3] memory) public pure { // ... }
}
</pre>
<p>In contrast, the array literal <code>[1, -2]</code> is invalid because it doesn’t comply with point 2., stating that the first expression’s type is a target type T for implicit conversion of other expressions. </p>
<p>Since our first expression is of type <code>uint8</code>, and the second expression is of type <code>int8</code> (including the negative numbers), the second expression cannot be implicitly converted to <code>uint8</code>. </p>
<p>To avoid a type error, we can declare our array literal as <code>[int8(1), -1]</code>, forcing the first expression to be of compatible type <code>int8</code>.</p>
<p>In a more specific case of using, e.g. two-dimensional array literals, we’d step on a problem of fixed-size memory arrays that cannot be converted into each other, regardless of the compatibility of base types. </p>
<p>We can get around this problem by explicitly specifying a common base:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0; contract C { function f() public pure returns (uint24[2][4] memory) { uint24[2][4] memory x = [[uint24(0x1), 1], [0xffffff, 2], [uint24(0xff), 3], [uint24(0xffff), 4]]; // The following does not work, because some of the inner arrays are not of the right type. // uint[2][4] memory x = [[0x1, 1], [0xffffff, 2], [0xff, 3], [0xffff, 4]]; return x; }
}
</pre>
<p>We cannot assign fixed-size memory arrays to dynamically-sized memory arrays, as shown by the example:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0; // This will not compile.
contract C { function f() public { // The next line creates a type error because uint[3] memory // cannot be converted to uint[] memory. uint[] memory x = [uint(1), 3, 4]; }
}
</pre>
<p>To initialize dynamically-sized arrays, we’d have to resort to assigning the elements individually, as in the example:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0; contract C { function f() public pure { uint[] memory x = new uint[](3); x[0] = 1; x[1] = 3; x[2] = 4; }
}
</pre>
<h2><a></a>Conclusion</h2>
<p>In this article, we learned even more about reference types, in particular, <code>bytes</code> and <code>string</code> arrays and concatenation, memory array allocation, and array literals.</p>
<ol>
<li>First, we explained the uniqueness of the arrays based on bytes and string types, and also touched on some of the similarities with the <code>akin</code> types.</li>
<li>Second, we’ve peeked into how to do string concatenation, comparison, and bytes concatenation.</li>
<li>Third, we discovered the specifics of allocating memory arrays and got introduced to the new operator.</li>
<li>Fourth, we got to know array literals with rules for determining the array literal base type. We also became aware of the invalid array literals and what can be done to make them valid.</li>
</ol>
<hr class="wp-block-separator has-alpha-channel-opacity"/>
<h2>What’s Next?</h2>
<p>This tutorial is part of our extended Solidity documentation with videos and more accessible examples and explanations. You can navigate the series here (all links open in a new tab):</p>
<div class="wp-container-1 is-content-justification-center wp-block-buttons">
<div class="wp-block-button"><a class="wp-block-button__link" href="https://blog.finxter.com/introduction-to-solidity-reference-types-and-arrays/" target="_blank" rel="noreferrer noopener"><img src="https://s.w.org/images/core/emoji/14.0.0/72x72/1f448.png" alt="?" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Prev Tutorial</a></div>
<div class="wp-block-button"><a class="wp-block-button__link" href="https://blog.finxter.com/solidity-deep-dive-syllabus-video-tutorial-resources/" target="_blank" rel="noreferrer noopener"><img src="https://s.w.org/images/core/emoji/14.0.0/72x72/261d.png" alt="☝" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Syllabus</a></div>
<div class="wp-block-button"><a class="wp-block-button__link" href="https://blog.finxter.com/solidity-deep-dive-syllabus-video-tutorial-resources/" target="_blank" rel="noreferrer noopener"><img src="https://s.w.org/images/core/emoji/14.0.0/72x72/1f449.png" alt="?" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Next Tutorial</a></div>
</div>
</div>
https://www.sickgaming.net/blog/2022/10/...-literals/