Can I use memset to initialize a 2 dimensional array? - c++

According to the C standard (SO link 1 and link 2) we cannot access an element of a row using out-of-bounds index:
int x[10][10] = ...; // initialize x
int q = x[0][10]; // This is an out-of-bounds access
Then is it valid to initialize the array using the following loop?
int *p = &x[0][0];
for (int i = 0; i < 100; ++i)
p[i] = 0;
If this is not valid, then is it valid to initialize x using memset(&x[0][0], 0, sizeof(x))?
int *p = &x[0][0];
memset(p, 0, sizeof(x))?
edit:
I wonder whether the answers are different in C++ as well..! :)

The loop is not valid, see the comments by #EricPostpischil .
Yes, the memset approach is valid too. But it is not preferred solution. It operates on individual bytes so it can only ever be reasonably used for zeroing the memory.
C++
Value initialization T array[10][10] = {}; zeroes the array of primitives types, calls default constructors for classes.
std::fill(p,p+100,value) for assigning a specific value.
There is not standard way how to initialize an array to non-zero values without listing them.
std::array<T,N> is the preferred way for arrays of known size.
C
cppreference
There is no special construct in C corresponding to value initialization in C++; however, = {0} (or (T){0} in compound literals) (since C99) can be used instead, as the C standard does not allow empty structs, empty unions, or arrays of zero length.
So, in case of nested arrays, use T array[10][10] = {{0}};.

You asked in title:
Can I use memset to initialize a 2 dimensional array?
Yes, as memset(...) only cares about byte count, you could use it like:
int x[10][10];
memset(&x, 0, sizeof(x));
But in C++, an empty initializer-list would do same, like:
int x[10][10] = {};
And in C since C99 (as mentioned in comments), we clould do instead:
int x[10][10] = {{0}};
Anyway, you say:
int q = x[0][10]; // This is an out-of-bounds access
Then asked is following valid:
int *p = &x[0][0];
for (int i = 0; i < 100; ++i)
p[i] = 0;
Well yes, but only because you do something as simple as setting to zero, a more complex logic could require you to loop 2 dimensionally, like:
for (int x = 0; x < 10; ++x) {
for (int y = 0; y < 10; ++y) {
myArray[x][y] = something_more_complex_here;
}
}

Related

Can't initialize array with pre-defined variable int

int shifts[c] = {0};
The c is defined. Error: shifts maybe not be initialized. Why? What am I doing wrong here? I think it has something to do with c, but I am not sure. If I can't use the current declaration, how do I get around it? I tried it with vectors first:
vector<bool> shifts(c, false)
But, it didn't work. Had bad_alloc error.
int max = 0, min = 10000;
for (int i = 0; i != 2*no_shifts; ++i) {
int x;
fin >> x;
time.push_back(x);
if (max < x)
max = x;
if (min > x)
min = x;
}
c = max - min + 1;
Based solely on c = max - min + 1; it seems that you are trying statically initialize an array without a compile time constant. Either use a dynamically allocated array or std::vector if you need something that can have it's size determined at runtime.
Edit: You may actually want to consider using std::bitset instead as an alternative container.

c style string and dynamic allocation in c++

I must implement a bunch of methods that allocates, modify and free a 2D array of c-style string. I cannot use string nor vectors nor any stl container.
getNewMat :
char*** getNewMat(int w, int h){
char*** newMat = new char**[h];
for(int i = 0 ; i < h ; i++){
newMat[i] = new char*[w];
for(int j = 0 ; j < w ; j++)
newMat[i][j] = NULL;
}
return newMat;
}
fillMat
void fillMat(char***mat, int x, int y, char* newEl){
mat[y][x] = newEl; //this will produce a segfault (even with good index)
}
showMat :
void showMat(char*** mat, int w, int h){
for(int i = 0 ; i < h ; i++){
for(int j = 0 ; j < w ; j++)
cout << mat[i][j];
}
cout << endl;
}
so, can anyone please tell me what's wrong with this?
In your fillMat method you do this:
mat[y][x] = newEl;
Where x and y are the dimensions of the two ranks of the array. That line will cause a segmentation fault because you're going outside the bounds of the array. mat is indexed from 0 to length - 1 and setting by x and y is going 1 outside the bounds of the array.
Maybe you meant to loop through and set them:
for (int i = 0; i < y; ++i)
{
for (int k = 0; k < x; ++k)
mat[i][k] = newEl;
}
Moreover, inside your showMat function you have this:
cout << showMat[i][j];
I think you meant for that to be mat:
cout << mat[i][j];
newMat[i][j] = NULL - it's a bad idea. In showMat you will try to dereference a NULL pointer - this is UB and may cause a segfault.
char* - it's not a string - it's just a pointer to char, that may points to memory location, where can be beginning of string. If you want to work with it like with a string, you should allocate memory for it too.
mat[y][x] = newEl - it's a bad idea too. As I already said, char* is not a string, so, you can't just use assignment operator to copy data from one C-string into another. You should use std::copy or std::strncpy.
Do not forget to free allocated memory after using.
You should implement your own string class - it's the better solution, I can see there. At least, because it simpler and easier to understand.
I must implement a bunch of methods that allocates, modify and free a
2D array of c-style string. ...snip... so, can anyone please tell me
what's wrong with this?
A "c-style string" isn't a type. It's a representation of data within a type. '\0'-terminated strings are typically stored within char arrays, but you could store one just as easily in a unsigned int array. For example:
unsigned int message[32] = { 0 };
strcpy((char *) message, "Hello, world!");
printf("%s\n", (char *) message);
I discourage programming like this, however micro-optimistic the benefits may seem. It's also possible to store a string in something that isn't an array. Consider that a char might be suitable for storing an empty string:
char x = '\0';
printf("%s\n", &x);
It's reasonable to assume that you meant "an array of array of array of char", when you said "2D array of c-style string". Let us carry on in that direction.
I don't know a lot about C++, but there's a list of property of arrays which you probably haven't thought about in your quest to mimic actual arrays. I'll summarise these using assertions:
#define x 7
#define y 13
#define z 1
char foo[x][y][z] = { 0 };
assert((char *) foo == foo[0]);
assert(sizeof foo == (char *) &foo[1] - (char *) &foo[0]);
assert(sizeof foo == x * y * z);
I'm not sure if you'll be able to solve your problem with any of these assertions passing in C++, but I'm open for any input from others as to hints as to how one might...
Arrays are contiguous. This means that newMat[x] + w and newMat[x+1], for values of x in 0 .. h-1. In your code, this isn't a reality, because you allocate newMat[x] and newMat[x+1] separately. Similarly, it is expected that newMay[0][y] == newMat[0][y+1] + n, where n is the maximum length of your strings. This can be a problem when using generic array sorting algorithms, because they might rely upon your arrays being contiguous.
The closest you might come to solving this problem seems to involve allocating only once per dimension, rather than h times for the first dimension and w for the second. This would look something like this:
char ***getNewMat(size_t w, size_t h, size_t n){
char ***newMat = new char **[h];
newMat[0] = new char *[h*w];
newMat[0][0] = new char[h*w*n];
for(size_t i = 0; i < h; i++){
newMat[i] = newMat[0] + i * w;
for (size_t j = 0; j < w; j++) {
newMat[i][j] = newMat[0][0] + i * w * n + j * n;
}
}
return newMat;
}
One side-effect of arrays being contiguous is that you can't assign C-style strings by merely changing the pointer within the array to point to a different location. The pointer is the result of a conversion from an array expression to a pointer expression which isn't an lvalue. As I said earlier, I don't know much about C++, but in C that means the following code can't compile:
char foo[x][y][z] = { 0 };
foo[a][b] = "hello";
However, the following code can compile:
char *foo[x][y] = { 0 };
foo[a][b] = "hello";
The former might constitute an array of C-style strings, but the latter can't because of the contiguity rule we've covered, and the fact that it starts off with most if it's elements pointing to NULL, a pointer which can't point to anything let alone strings. There might be some operator overloading magic you can perform to permit the former to compile. I'm also open for any hints in the right direction to provide an example for the OP, here.

C++ Dynamic Array 1 dimension non dynamic

Been awhile since I've programmed in C++ however I have a slight problem that I'm trying to figure out.
Is it possible to make a 2 by 2 dynamic array where 1 dimension is not dynamic?
For example
array[2][Dynamic]?
It seems like a waste to make array[dynamic][dynamic] and when I only need to use the first [0][dynamic] and second [1][dynamic] values.
Should I use another data structure?
Thanks.
Arrays and pointers are basically equivalent, so you can achieve this with an array of pointers:
int* array[2];
array[0] = new int[x];
array[1] = new int[y];
You can still access it as you would multidimensional array:
array[0][x-1] = z;
This works in C++11:
std::array<std::vector<MyClass>,2> arr;
Or you could use a c-style array of vectors
std::vector<MyClass> arr[2];
Sure but it has to be dynamic in the first dimension.
Like this for instance
typedef int two_int_array[2];
two_int_array* a = new two_int_array[n];
for (int i = 0; i < n; ++i)
{
a[i][0] = 1;
a[i][1] = 2;
}
Of course the better way in general is to use vectors. Since you can't have a vector of arrays, a vector of structs might be better for your case.
struct two_int_struct
{
int value[2];
};
std::vector<two_int_struct> a(n);
for (int i = 0; i < n; ++i)
{
a[i].value[0] = 1;
a[i].value[1] = 2;
}

Pointing to a 2-dimensional array

I'm trying to write code that has a pointer point to a 2-dimensional array.
My main purpose is for not just one asd array, like I would like to point 5 array each of which is 2 dimensional.
int asd1[2][2];
int asd2[2][2];
int *se;
se[0] = asd1;
se[1] = asd2;
Use se = asd[0];
The reason is that the symbol asd yields not a pointer to an int but rather a pointer to a one-dimensional array of ints.
#Mig's solution may be good, too. It depends on what you want. In my experience, it tends to work better when you treat a two-dimensional array of a basic type like int as though it were a one-dimensional of length n*n. (This is expecially true in numerical work, where you are likely to call BLAS and LAPACK, but may be true elsewhere, as well. You probably aren't doing numerical work here, but, well, try #Mig's and mine both, and see which you don't prefer. Good luck.)
You can do this:
#include<stdio.h>
int main()
{
int asd[2][2] = {{0,1},{2,3}};
int (*se)[2]; // a pointer (*se) to an array (2-element array, but only you know it, not the compiler) of array-of-two-integers [2]
se = asd;
printf("%d %d\n%d %d\n", se[0][0], se[0][1], se[1][0], se[1][1]);
return 0;
}
or:
#include<stdio.h>
int main()
{
int asd[2][2] = {{0,1},{2,3}};
int (*se)[2][2]; // a pointer (*se) to a 2-element array (first [2]) of two element array (second [2]) of ints
se = &asd;
printf("%d %d\n%d %d\n", (*se)[0][0], (*se)[0][1], (*se)[1][0], (*se)[1][1]);
return 0;
}
You want something like this:
int asd[2][2];
int (*se)[2] = asd;
This is equivalent to
int (*se)[2] = &asd[0];
because asd decays to a pointer to its first element in this context.
The key thing to bear in mind is that the type of asd[0] is int[2], not int*, so you need a pointer to an int[2] (i.e. int (*)[2]) and not a pointer to an int* (i.e. int**).
Incidentally, you can make an int* point to the first element of the asd[0] if you like:
int *p = &asd[0][0]; // or just = asd[0];, because it decays to &asd[0][0];
but accessing the other elements of the 2D array as if it were a 1D array, e.g. p[2], would be undefined behaviour.
As a more general point, it's often better to eschew using raw C-style arrays altogether if you can help it. You might want to investigate std::array or std::vector, depending on your needs.
If you were allocating that array dynamically, you could do something like this:
#include <stdio.h>
#include <stdlib.h>
#define SIZE 10
int main() {
int i;
int **asd;
asd = (int **)malloc(sizeof(int *) * SIZE);
for (i = 0; i < SIZE; i++) {
asd[i] = (int*)malloc(sizeof(int) * SIZE);
}
int **se;
se = asd;
se[0][1] = 10;
printf("%d %d\n", se[0][1], asd[0][1]);
for (i = 0; i < SIZE; i++) {
free(asd[i]);
}
free(asd);
return 0;
}
EDIT: My first answer was wrong, here's what I had said:
You need a pointer to a pointer, since your array is 2-dimensional:
int asd[2][2];
int **se;
se = asd;
Now you should be able to:
se[0][1] = 10;

Initialization of 2D array with dynamic number of rows and fixed number of columns. C++

I'm having problem with creating my 2D dynamic array in C++. I want it to have dynamic number (e.g. numR) of "rows" and fixed (e.g. 2) number of "columns".
I tried doing it like this:
const numC = 2;
int numR;
numR = 10;
double *myArray[numC];
myArray = new double[numR];
Unfortunately, it doesn't work. Is it possible to do it in such a way?
Of course I could use double **myArray and initialize it as if both dimensions are dynamic (with numC used as limiter in loop) but I would like to avoid it if possible.
Thanks in advance.
Is it possible to do it in such a way?
Yes:
double (*myArray)[numC] = new double[numR][numC];
// ...
delete[] myArray;
This may look a little unusual, but 5.3.4 ยง5 clearly states:
the type of new int[i][10] is int (*)[10]
Note that many programmers are not familiar with C declarator syntax and will not understand this code. Also, manual dynamic allocation is not exception safe. For these reaons, a vector of arrays is better:
#include <vector>
#include <array>
std::vector<std::array<double, numC> > vec(numR);
// ...
// no manual cleanup necessary
Replace std::array with std::tr1::array or boost::array, depending on your compiler.
Why not use a std::vector, and take advantage of its constructor:
std::vector<std::vector<int> > my2Darray(2, std::vector<int>(10));
my2Darray[0][0] = 2;
There needs to be a loop since you need to create an array for every column.
I think what you're after is:
double *myArray[numC];
for (int i = 0; i < numC; i++) {
myArray[i] = new double[numR];
}
// some code...
// Cleanup:
for (int i = 0; i < numC; i++) {
delete [] myArray[i];
}
This declares an array of pointers (to double) with numC elements, then creates an array of doubles with numR elements for each column in myArray. Don't forget to release the memory when you're done with it or you'll have memory leaks.
Your indexes should be row, then column.
double** myArray = new double*[numR];
for( unsigned int i = 0; i < numR; i++ ) {
myArray[i] = new double[numC];
}
Access row 2, column 5:
myArray[2][5];