Dynamic array of char arrays

The title might seem a little confusing but I'll try to explain. I have a struct and I know I'm getting a certain number of char arrays, which have a constant size, so to give an example:

1. abcd
2. bcde
3. cdef
etc.

So far I have searched on different forums and I have the following code:


1
2
3
struct a{
  char(*arr)[4];
};



This seems to compile, but I'm not sure how to initialise and use it afterwards, not even sure if it is correct. Any idea of how to achieve something like this? Thanks in advance.
Last edited on
Do not forget to leave room for the 0 end of string marker that C uses. You need [5].
to use it you need to allocate memory for it manually and release it after

I will be honest, I do not know how to allocate/use the thing you made either. this is how I know to do it:
1
2
3
4
5
6
7
8
9
10
11
12
13
int main()
{
   	
  typedef char c4[5] ;
  struct a {  c4* many;};
  a s;
  s.many  = new c4[100];
  
  sprintf(s.many[42], "fubr");
  cout << s.many[42];  
  delete[] s.many;   
}   

you can, and probably should, move the allocation and deallocation into a constructor/destructor for the struct.


But that aside, do you have to do this using C like constructs, or can you use c++?
C++ would just say
struct a
{
vector<string> data;
};
...
data.push_back("abcd"); //add items to the vector.
...
cout << data[i]; //works like array of strings here.
Last edited on
I don't really get what you're trying to do. But consider as C:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>

const size_t arrsze = 5;

struct A {
	const char* arr[arrsze] {};
};

int main()
{
	A a1;

	a1.arr[0] = "qwer";
	a1.arr[1] = "asdf";

	printf("%s\n%s\n", a1.arr[0], a1.arr[1]);
}


PS You can do things like this - but why??

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>

const size_t elemsz = 5;
const size_t arrsz = 4;

struct A {
	const char (*arr)[elemsz] {};
};

int main()
{
	const char B[arrsz][elemsz] = {"qwer", "wert", "asdf", "zxcv"};

	A a1(B);

	printf("%s  %s\n", *a1.arr, *(a1.arr + 1));
}


Note that (*arr) means pointer to array. Leaving off the () means array of pointers. The two are not the same!
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <random>
using namespace std;

const int Size = 4;

struct A {
    char(*arr)[Size];
};

int main() {
    int n;
    cout << "How many? ";
    cin >> n;
    A a;
    a.arr = new char[n][Size];
    
    default_random_engine rnd(random_device{}());
    uniform_int_distribution<> dist(0, 25);

    for (int i = 0; i < n; ++i)
        for (int j = 0; j < Size; ++j)
            a.arr[i][j] = char(dist(rnd) + 'a');

    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < Size; ++j)
            cout << a.arr[i][j] << ' ';
        cout << '\n';
    }

    delete[] a.arr;
}

It depends on if you're using C or C++. C++ can produce something that's a little easier to read.

And as jonnin showed, typedef is your friend.

In C++ you can write:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
struct a {
    typedef char[5] c4_t; // 4 + null terminator
    c4_t* array;

    // hide memory management in the struct
    a(size_t size) : array(new c4_t[size]) {}
    ~a() { delete [] array; }
    a(const a& ) = delete;
    a& operator=(const a& ) = delete;
    a(a&& m) : array(n.array) { n.array = nullptr; }
    a& operator(a&& n) {
        delete array;
        array = n.array;
        n.array = nullptr;
    }
}

int main() {
    const char* words[] = { "pear", "peer", "bear", "beer", nullptr };
    constexpr size_t size{4};

    a a4(size);
    for (size_t i 0; i != size; ++i)
        strcpy(a4.array[i], words[i]);
}

Last edited on
@kbw - I think you're been using my old faulty keyboard! :)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
struct a {
	//typedef char c4_t[5]; // 4 + null terminator
	using c4_t = char[5];
	c4_t* array;

	// hide memory management in the struct
	a(size_t size) : array(new c4_t[size]) {}
	~a() { delete[] array; }
	a(const a&) = delete;
	a& operator=(const a&) = delete;
	a(a&& m) : array(m.array) { m.array = nullptr; }
	a& operator=(a&& n) {
		delete [] array;
		array = n.array;
		n.array = nullptr;
	}
};

int main() {
	const char* words[] = {"pear", "peer", "bear", "beer", nullptr};
	constexpr size_t size {4};

	a a4(size);

	for (size_t i = 0; i != size; ++i)
		strcpy(a4.array[i], words[i]);
}

seeplus :)
Hi, sorry that I have been inactive, it's just that I've been tasked with doing 10 different things since and I totally forgot about this issue.

I didn't leave space for the termination char on purpose, since I'm going to create another string out of those, which should not containt anything else except the relevant characters, because then I have to send it to a server, where it will get encoded. So if I had a termination char in there then the end result would be faulty.

typdef is definitely a good idea, no clue why I didn't think of it myself. Oh well...

Thanks for the answers everyone :)
that will cause you some troubles. If you leave off the space for the 0 character, you MUST NOT use standard C string functions that depend on either it being there (strlen, etc) or that put it there as a result (sprintf, strcpy, strcat, etc).

what I recommend in that case is to have a temporary C string that you can do these operations safely with, and use a memcpy to move the 4 letters you want to keep from the result into your target storage. Or if you do not need the C string functions, just dump the letters you need and keep going is fine too. Just be careful with it.
Last edited on
Topic archived. No new replies allowed.