convert non-null-terminated char-array to std::string

std::string ccy (ptr->ccy, ptr->ccy+3); //using a special string() ctor

my ptr->ccy is the address of a 3-char array, but it’s immediately followed by other chars belonging to another field, in a tightly packed struct without padding. If you simply pass ptr->ccy to string() ctor, your string will take in many extra chars until a null terminator.


strncpy^strcpy^strlcpy #padding nulls claims that strncpy is not safe, but I am not sure. The strncpy() API is well defined, while strlcpy is a BSD extension and not even available in my linux. May not be in glibc.

One key difference between strcpy vs strncpy is the implicit \0 terminator —

strcpy() unconditionally appends a single null (\0), whereas strncpy won’t. strncpy() appends enough padding nulls IIF input array contains a null within first “n” slots.

array^pointer variables types: indistinguishable

  • int i; // a single int object
  • int arr[]; //a nickname of the starting address of an array, very similar to a pure-address const pointer
  • int * const constPtr;
  • <— above two data types are similar; below two data types are similar —->
  • int * pi; //a regular pointer variable,
  • int * heapArr = new int[9]; //data type is same as pi

[13]arrayName^ptrVar differences tabulated

See other posts why an array name is a permanent name plate on a permanently allocated room in memory. Once you understand that, you know
– can’t move this name plate to another room
– can’t put a 2nd name plate on the same room
– can’t put this array name on the LHS of assignment

I feel overall, in most everyday contexts you can treat the array name in this example as if it’s a variable whose type is int*. However, the differences lurk in the dark like snakes, and once bitten, you realize there are many many differences. The 2 constructs are fundamentally different.

Q: how to edit the below html table structure (content is easy)?
A: edit the html
A: copy paste to ms-word

ptr to heap array ptr-var array-name (array not on heap)
declaration array-new int* p//allocate 32bit int arr[3]//allocate 3 ints
declared as a struct/class field same as ptr-var 4-bytes onsite entire array embedded onsite
declared as func param var no such thing common converted a ptr-var by compiler
initialize probably not supported char* p=”abc”;// puts the literal string in RO memory char arr[]=”xyz”; //copying the literal string from RO memory to stack/heap where the array is allocated. The new copy is editable.
object passed as func arg same as ptr-var common converted to &arr[0]
dereference same as ptr-var common gives the first int element value. P119[[primer]]
address of same as ptr-var double ptr &arr[0]==&arr==arr. See headfirstC post and also
rebind/reseat same as ptr-var common syntax error
add alias to the pointee same as ptr-var common unsupported
as LHS (not as func param) same as ptr-var common. Reseat syntax error

char-array dump in hex digits: printf/cout

C++ code is convoluted. Must cast twice!

// same output from c and c++: 57 02 ff 80
void dumpBufferPrintf(){
  static const char tag[] = {'W', 2, 0xFF, 0x80};
  cout << hex << setfill('0') ;
  for(int i = 0; i< sizeof(tag)/sizeof(char); ++i)
    printf("%02hhx ", tag[i]);
  printf ("\n");
#include <iostream>
#include <sstream> //stringstream
#include <iomanip> //setfill

//This function was also used to dump a class instance. See below
void dumpBufferCout(const char * buf, size_t const len){
                std::stringstream ss;
                ss << std::hex << std::setfill('0');
                for(size_t i=0; i<len; ++i){
                          if (i%8 == 0) ss<< "  ";
                          ss<<std::setw(2)<< (int)(unsigned char) buf[i]<<" ";
dumpBufferCout((const char*)&myStruct, sizeof(myStruct));

impressive container dumper #operator<<

Compared to the standard dump(), This is slightly harder to write but convenient to use and impressive in an interview:

  • operator template, agnostic of the payload type
  • operator overload
  • setw()

To support other containers beside list, you can copy paste this function and change the 2nd arg type. Thanks to the auto keyword, nothing else needs change.

When I attempted to consolidate to a single function template to handle all container types, then cout<<“any_string” also picks up this function inadvertently 😦 is my tested code


std::vector memory allocation/free: always heap@@ is concise.

  • The vector “shell” can be on stack or heap or static memory, as you wish.
  • The continuous array (payload objects) are always allocated on the heap, so that the vector can grow or deallocate them.

Deallocation is explained in

range-check in c++ vector^raw array

[[safe c++]] points out that static array or dynamic array are both (unfortunately) silent about access beyond their limits. Vector has operator[] and at() —

[[]] says c++ new array type supports .size()…

#include <iostream>
#include <vector>
using namespace std;

int main(){
    vector<int> v;
    size_t sz = v.size();
        cout<<v[0]<<" "<<v[sz]<<" <- operator[]: out-of-range treated as non-error!"<<endl;
        cout<<<<" <- at(): throws:)"<<endl;
    }catch(exception & ex){
        cerr<<"Must catch by ref (what() virtual) " << ex.what()<<endl;

std::array+alternatives #RAII dtor

feature wish list — RAII; fixed size; bound check compares vector ^ unique_ptr ^ std::array. Conclusion — Vector is more powerful, more versatile, more widely useful, less restrictive. std::array is

All alternatives to std::array:

  • vector and raw array
  • boost::scoped_array and boost::shared_array — least quizzed.
  • std::unique_ptr<int[]> dynArr(new int[theSize]) # can be allocated on heap at runtime, and you don’t need to call delete[]

The dtor in each data structure is a key feature if you want RAII:

  1. std::array — dtor probably destroys each element one by one. No q(delete) called since the elements could be on stack
  2. scoped_array — dtor calls delete[], which is a key difference from scoped_ptr, according to my book [[beyond the c++ standard lib]]
  3. vector — dtor uses its allocator, which very likely calls delete[] since vector uses heap for the underlying growable array.
  4. unique_ptr<T[]> — yes as expected. This valgrind experiment shows the array-specialization uses delete[], whereas the vanilla instance uses regular q(delete).