double pointer memory allocation - c++

I am currently trying to allocate the same amount of memory for a double pointer. I take in a char** and want to use a bubble sort on that char** . So I create a temp char** and now I'm wondering how to correctly allocate enough memory so that I can return that temp char** to another method.
I know the way I'm allocating right now doesn't look right and it certainly doesn't work...otherwise I wouldn't be asking this question. If someone could respond with some helpful advice, I would greatly appreciate it!
char** bubble_sort(char **filenames, int n)
{
int i;
char **new_list;
new_list = malloc(sizeof(filenames));
for (i = 0; i < n; i++)
{
// malloc(file_list.size * sizeof(int));
new_list[i] = filenames[i];
}
for (i = 0; i < n; i++)
{
printf("%d: %s\n", i, new_list[i]);
}
int x;
int y;
for(x=0; x<n; x++)
{
for(y=0; y<n-1; y++)
{
if(new_list[y]>new_list[y+1])
{
char *temp = new_list[y+1];
new_list[y+1] = new_list[y];
new_list[y] = temp;
}
}
}
for (i = 0; i < n; i++)
{
printf("%d: %s\n", i, new_list[i]);
}
return new_list;
}

char** bubble_sort(char **filenames, int n)
{
int i;
char **new_list;
new_list = malloc(sizeof(filenames));
This code allocates enough space to store a single pointer (sizeof(filenames) is mostly likely 4), and gives the address of that pointer to new_list. If you want to access what new_list points to as an array (and I know you do, because you tried to do just that below), you'll need to allocate enough space for its elements.

Here is the working copy of the program:
#include <cstdio>
#include <cstdlib>
#include <cstring>
char** bubble_sort(const char **filenames, int n)
{
int i;
char **new_list;
new_list = (char**) malloc(sizeof(*new_list) * n);
for (i = 0; i < n; i++)
{
new_list[i] = (char*) filenames[i];
}
printf("Initial list:\n");
for (i = 0; i < n; i++)
{
printf("%d: %s\n", i, new_list[i]);
}
int x;
int y;
printf("List is sorted:\n");
for(x=0; x<n; x++)
{
for(y=0; y<n-1; y++)
{
if(strcmp(new_list[y],new_list[y+1])>0)
{
char *temp = new_list[y+1];
new_list[y+1] = new_list[y];
new_list[y] = temp;
}
}
}
for (i = 0; i < n; i++)
{
printf("%d: %s\n", i, new_list[i]);
}
return new_list;
}
int main(){
const char *ar[5]={
"eee", "aaa", "bbb", "ccc", "ddd",
};
bubble_sort(ar, 5);
return (0);
}
Still, keep in mind that your programming style resembles more to C than C++ (which is not always a bad thing).
If you want to allocate new strings for your array elements, you should change the first for like this:
for (i = 0; i < n; i++)
{
//new_list[i] = (char*) filenames[i];
new_list[i] = (char*) malloc(sizeof(**new_list) * (strlen(filenames[i]) + 1));
strcpy(new_list[i], filenames[i]);
}
And this is the C version (first one was the C++ version). Note that the string array has all its elements newly allocated, and is not using the initial strings from the input parameter.:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char** bubble_sort(char **filenames, int n)
{
int i;
char **new_list;
new_list = malloc(sizeof(*new_list) * n);
for (i = 0; i < n; i++)
{
//new_list[i] = (char*) filenames[i];
new_list[i] = malloc(sizeof(**new_list) * (strlen(filenames[i]) + 1));
strcpy(new_list[i], filenames[i]);
}
printf("Initial list:\n");
for (i = 0; i < n; i++)
{
printf("%d: %s\n", i, new_list[i]);
}
int x;
int y;
printf("List is sorted:\n");
for(x=0; x<n; x++)
{
for(y=0; y<n-1; y++)
{
if(strcmp(new_list[y],new_list[y+1])>0)
{
char *temp = new_list[y+1];
new_list[y+1] = new_list[y];
new_list[y] = temp;
}
}
}
for (i = 0; i < n; i++)
{
printf("%d: %s\n", i, new_list[i]);
}
return new_list;
}
int main(){
char *ar[5]={
"eee", "aaa", "bbb", "ccc", "ddd",
};
bubble_sort(ar, 5);
return (0);
}

filenames is a pointer to pointer to char, therefore on this line...
new_list = malloc(sizeof(filenames));
...you're allocating the amount of the size of the pointer (to pointer), which isn't what you want.
You probably want malloc(sizeof(filenames) * n); which will give you the space for n pointers.

This is somewhat of a duplicate. See: Creating `char ***data`?
There are serious memory performance issues with respect to allocating at char** for a 2D array. Better to use a char* and a indexing scheme. In this way you get a contiguous chunk of memory. You can also use a one-D std::vector with such a scheme.
If you must allocate a char**, the for loop is all you can do AFAIK. But at least make a subroutine out of that! :)

Related

C++ program behavior on pointers to integer array

Can anyone please explain why the loop only execute once!!
The for loop executes once and never reaches end of the programm
and if you've got some time to review my mistakes then please point out mistakes because i know this is not how it is done!!
using namespace std;
#include<iostream>
int* rotate(int* ar,int d,int n)
{
int tmp[n];
d = d%n;
for (int i = 0; i < n; ++i)
{
tmp[i] = ar[(i+d)%n];
}
free(ar);
return tmp;
}
int main(int argc, char const *argv[])
{
int arr[] = {1,2,3,4,5};
int *a;
int n = sizeof(arr)/sizeof(arr[0]);
a = rotate(arr,4,n);
cout<<endl;
for (int i = 0; i < n; ++i)
{
cout<<i<<endl;
cout<<a[i]<<endl;
}
cout<<"End";
return 0;
}
Lets take it apart...
int* rotate(int* ar,int d,int n)
{
int tmp[n]; // 1
d = d%n;
for (int i = 0; i < n; ++i)
{
tmp[i] = ar[(i+d)%n];
}
free(ar); // 2
return tmp; // 3
}
int tmp[n]; is not standard C++. If you do not want to use std::vector the proper replacement would be a dynamically allocated array.
You call free with a pointer that was not allocated via malloc, which invokes undefined behavior. In C++ you shouldn't be using free and malloc at all, but rather new and delete. And also new and delete only for such exercise. Otherwise use smart pointers.
You return a pointer to a local variable. The pointer is dangling and using it in main invokes undefined behavior.
You can't simply replace the static array arr in main with something else in the function. A function called rotate is not expected to create a new array or delete the one that was passed (also because like in your case it is just not possible).
There are different ways to fix your code. I choose to make rotate rotate the array "in-place". However, as you can see, the implementation actually uses an additional array of same size. I leave it to you to figure out how to change it to use less additional memory:
#include <iostream>
using std::cout;
using std::endl;
void rotate(int* ar,int d,int n)
{
int* tmp = new int[n];
d = d%n;
for (int i = 0; i < n; ++i)
{
tmp[i] = ar[(i+d)%n];
}
for (int i = 0; i < n; ++i)
{
ar[i] = tmp[i];
}
}
int main(int argc, char const *argv[])
{
int arr[] = {1,2,3,4,5};
int n = sizeof(arr)/sizeof(arr[0]);
rotate(arr,4,n);
cout<<endl;
for (int i = 0; i < n; ++i)
{
cout<<i<<endl;
cout<<arr[i]<<endl;
}
cout<<"End";
return 0;
}
This is how you can do the same using std::rotate:
#include <array>
#include <iostream>
#include <algorithm>
int main(int argc, char const *argv[])
{
int arr[] = {1,2,3,4,5};
int n = sizeof(arr)/sizeof(arr[0]);
std::rotate(std::begin(arr),std::begin(arr)+4,std::end(arr));
for (int i = 0; i < n; ++i)
{
std::cout << i << std::endl;
std::cout << arr[i] << std::endl;
}
std::cout<<"End";
}
... it even uses pointers ;)

Extract pair numbers from array

Good evening, folks.
I'm currently experiencing difficulties with extracting pair numbers from an array. I have the following code:
#include <iostream>
using namespace std;
int *paire(int *d, int length) {
int counter = 0;
int position = 0;
for (int i=0; i<length; i++) {
if (d[i] % 2 ==0)
counter++;
}
int *k = new int[counter];
for (int i=0; i<length; i++) {
if (d[i] % 2 ==0) {
k[position] = d[i];
position++;
}
}
return k;
}
int main() {
int b[8] = {1,2,3,4,5,6,7,8};
int *array1 = paire(b,8);
for (int i=0; i<5; i++) { // how can I point here to the counter in paire() ?
cout<<array1[i];
}
delete[] array1;
return 0;
}
So I think I've got it right with initializing the new array in function paire, but I'm having difficulties to iterate through the array.
P.S. I'm first year in university, so I would really be thankful if you can keep the same simplicity in the answers. Thanks in advance!
It appears that you need to return 2 separate values: the number of even numbers in the array b, and the address of the newly allocated memory that is storing exclusively those even numbers.
Since you can not return multiple variables, one solution that does minimal modification to your code would be as follows.
int *paire(int *d, int length, int& counter) {
counter = 0;
// rest of your function remains unchanged
// ...
}
int main() {
int b[8] = {1,2,3,4,5,6,7,8};
int evenNumbers;
int *array1 = paire(b,8, evenNumbers);
for (int i=0; i<evenNumbers; i++) {
cout<<array1[i];
}
delete [] array1;
return 0;
}
Alternatively, you can return the value in counter and send the reference to the int* variable as an argument to paire function. Or, you can declare paire to have return type void and use references to pass back both the values.
You can further simplify your function by allocating to that of the length and returning the counter by an output parameter.
#include <iostream>
using namespace std;
int *paire(int *d, int length, int &counter) {
counter = 0;
int *k = new int[length]; // allocate for the maximum memory
for (int i = 0; i < length; ++i) {
if (d[i] % 2 == 0) {
k[counter++] = d[i];
}
}
return k;
}
int main() {
int b[8] = {1,2,3,4,5,6,7,8};
int counter = 0;
int *array1 = paire(b,8, counter);
for (int i=0; i<counter; i++) { // how can I point here to the counter in paire() ?
cout<<array1[i] << " ";
}
delete [] array1;
return 0;
}
But please note that as others have already pointed out this method is quite error prone in the sense that it leaves the responsibility to the client to delete the internal memory used by paire function.

Reversing an array using pointers

I have this program that makes and populates an array. Then it is sent to a function called reverse, which reverses the order in the array. The compiler keeps giving errors. I'm not quite sure why.
CODE
void reverse(int* array, int size) {
for (int i = 0; i < size/2; i++) {
int temp = array[i];
array[i] = array[size-i];
array[size-i] = temp;
} // end of for loop
} // end of reverse
int main( int argc, char** argv ) {
int array[8];
// get and print size of the array
int size = sizeof(array) / sizeof(array[0]);
printf("Size is %d\n", size);
// populate array
for (int i = 0; i < size; i++) {
array[i] = i;
} // end of for loop
// display array before reversing
for (int i = 0; i < size; i++) {
printf("%d ", array[i]);
} // end of for loop
// new line
printf("\n");
// reverse the array
reverse(&array, size);
// display the array again after reversing
for (int i = 0;i < size; i++) {
printf("%d ", array[i]);
} // end of for loop
} // end of main
It keeps giving me this error
main.cc:17:14: error: indirection requires pointer operand ('int' invalid)
int temp = *array[i];
^~~~~~~~~
main.cc:18:3: error: indirection requires pointer operand ('int' invalid)
*array[i] = *array[size-i];
^~~~~~~~~
main.cc:18:15: error: indirection requires pointer operand ('int' invalid)
*array[i] = *array[size-i];
^~~~~~~~~~~~~~
main.cc:19:3: error: indirection requires pointer operand ('int' invalid)
*array[size-i] = temp;
^~~~~~~~~~~~~~
4 errors generated.
make: *** [main.o] Error 1
I did solve this problem a little differently, maybe you will use this code:
#include <iostream>
void displayArray(int table[], int size);
void rev(int table[], int size);
void fillTheArray(int table[], int size);
int main(int argc, char** argv) {
int myArray[8];
int size = sizeof(myArray) / sizeof(myArray[0]);
std::cout << "Array size is: " << size << std::endl;
fillTheArray(myArray, size);
displayArray(myArray, size);
std::cout << std::endl;
rev(myArray, size);
displayArray(myArray, size);
std::cin.get();
return 0;
}
void fillTheArray(int table[], int size) {
for (int i = 0; i < size; i++) {
table[i] = i;
}
}
void displayArray(int table[], int size) {
for (int i = 0; i < size; i++) {
std::cout << table[i] << " ";
}
std::cout << std::endl;
}
void rev(int table[], int size) {
int *start = table;
int *end = table + (size - 1);
for (int i = 0; i < size; i++) {
if (start < end) {
int temp = *end;
*end = *start;
*start = temp;
}
start++;
end--;
}
}
I can see two errors in this code. First is: wrong way of passing parametr to function:
// reverse the array
reverse(&array, size);
you should do this just like this(array name is pointer to first element of this array):
reverse(array, size);
Second problem is with reverser - you try to access some random memory outside arrar range:
array[i] = array[size-i];
Remember that in C++ array index's start with 0 not 1. So if your array is size of 8 - largest insext of this array is 7 (0, 1, 2, 3, 4, 5, 6, 7). Your code should look like this:
array[i] = array[size -i -1];
And it should work as you expected.
It is my solution with pointers:
void reverse(int arr[], int count)
{
int* head = arr;
int* tail = arr + count - 1;
for (int i = 0; i < count/2; ++i)
{
if (head < tail)
{
int tmp = *tail;
*tail = *head;
*head = tmp;
head++; tail--;
}
}
for (int i = 0; i < count; ++i)
{
std::cout << arr[i] << " ";
}
}
or just use functions build in C++: std::reverse in 'algorithm' library.
It's a lot of examples on stackoverflow with this kind of examples:
Reverse Contents in Array
You have fixed most of the compiler errors in your code except one.
The line
reverse(&array, size);
should be
reverse(array, size);
After that is fixed, you have to fix logic errors in reverse.
You are using the wrong index for accessing the upper half of the array.
void reverse(int* array, int size) {
for (int i = 0; i < size/2; i++) {
int temp = array[i];
array[i] = array[size-i]; // When i is 0, you are accessing array[size]
// That is incorrect.
array[size-i] = temp;
} // end of for loop
} // end
You need to use
void reverse(int* array, int size) {
for (int i = 0; i < size/2; i++) {
int temp = array[i];
array[i] = array[size-i-1];
array[size-i-1] = temp;
}
}
Another way to approach the algorithm would be to use two indices.
void reverse(int* array, int size) {
for (int i = 0, j = size-1; i < j; ++i, --j) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
Working program: http://ideone.com/ReVnGR.
You're passing **int instead of *int to the reverse method:
reverse(&array, size);
Pass it like that:
reverse(array, size);

Pass By Reference Multidimensional Array With Unknown Size

How to pass by reference multidimensional array with unknown size in C or C++?
EDIT:
For example, in main function I have:
int main(){
int x, y;
int arr[x][y];
// pass_by_ref(/* passing just arr[][] by reference */);
}
and the function:
void pass_by_ref(/* proper parameter for arr[][] */){
// int size_x_Arr = ???
// int size_y_arr = ???
}
How to implement the commented line?
Simply put, you can't. In C, you can't pass by reference, since C has no references. In C++, you can't pass arrays with unknown size, since C++ doesn't support variable-lenght arrays.
Alternative solutions: in C99, pass a pointer to the variable-length array; in C++, pass a reference to std::vector<std::vector<T>>.
Demonstration for C99:
#include <stdio.h>
void foo(int n, int k, int (*arr)[n][k])
{
int i, j;
for (i = 0; i < n; i++) {
for (j = 0; j < k; j++) {
printf("%3d ", (*arr)[i][j]);
}
printf("\n");
}
}
int main(int argc, char *argv[])
{
int a = strtol(argv[1], NULL, 10);
int b = strtol(argv[2], NULL, 10);
int arr[a][b];
int i, j;
for (i = 0; i < a; i++) {
for (j = 0; j < b; j++) {
arr[i][j] = i * j;
}
}
foo(a, b, &arr);
return 0;
}
Demonstration for C++03:
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
void foo(std::vector < std::vector < int > > &vec)
{
for (std::vector < std::vector < int > >::iterator i = vec.begin(); i != vec.end(); i++) {
for (std::vector<int>::iterator j = i->begin(); j != i->end(); j++) {
std::cout << *j << " ";
}
std::cout << std::endl;
}
}
int main(int argc, char *argv[])
{
int i = strtol(argv[1], NULL, 10);
int j = strtol(argv[2], NULL, 10);
srand(time(NULL));
std::vector < std::vector < int > > vec;
vec.resize(i);
for (std::vector < std::vector < int > >::iterator it = vec.begin(); it != vec.end(); it++) {
it->resize(j);
for (std::vector<int>::iterator jt = it->begin(); jt != it->end(); jt++) {
*jt = random() % 10;
}
}
foo(vec);
return 0;
}
H2CO3's solution will work for C99 or a C2011 compiler that supports VLAs. For C89 or a C2011 compiler that doesn't support VLAs, or (God forbid) a K&R C compiler, you'd have to do something else.
Assuming you're passing a contiguously allocated array, you can pass a pointer to the first element (&a[0][0]) along with the dimension sizes, and then treat it as a 1-D array, mapping indices like so:
void foo( int *a, size_t rows, size_t cols )
{
size_t i, j;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
a[i * rows + j] = some_value();
}
}
}
int main( void )
{
int arr[10][20];
foo( &arr[0][0], 10, 20 );
...
return 0;
}
This will work for arrays allocated on the stack:
T a[M][N];
and for dynamically allocated arrays of the form:
T (*ap)[N] = malloc( M * sizeof *ap );
since both will have contiguously allocated rows. This will not work (or at least, not be guaranteed to work) for dynamically allocated arrays of the form:
T **ap = malloc( M * sizeof *ap );
if (ap)
{
size_t i;
for (i = 0; i < M; i++)
{
ap[i] = malloc( N * sizeof *ap[i] );
}
}
since it's not guaranteed that all the rows will be allocated contiguously to each other.
This is a sort of comment to the good answer of #John Bode
This will not work (or at least, not be guaranteed to work) for
dynamically allocated arrays of the form:
But this variant will:
T **ap = malloc( M * sizeof *ap );
if (ap) return NULL; ---> some error atention
if (ap)
{
ap[0] = malloc( M * N * sizeof *ap[i] );
if (ap[0]) { free(ap); return NULL;} ---> some error atention
size_t i;
for (i = 1; i < M; i++)
{
ap[i] = ap[0] + i * N;
}
}
After use :
free(ap[0]);
free(ap);
for T being int you call foo exactly als for the array int ap[M][N];
foo( &ap[0][0], M, N);
since you guaranteed that all the rows are allocated contiguously to each other.
This allocation is a litter more efficient.
John Bode's explanation is very good, but there is a little mistake:
it should be
i * cols + j
instead of
i * rows + j
If you really want references, then it's only in C++.
En example of a two-dimensional int array passed by reference
void function_taking_an_array(int**& multi_dim_array);
But the reference doesn't have any advantage, so simply use :
void function_taking_an_array(int** multi_dim_array);
I would advice you to use a container to hold your array.

C++ Replace string to char[]

I have the following c++ program that multiple 2 large numbers :
#include <iostream>
#include <string>
#define OVERFLOW 2
#define ROW b_len
#define COL a_len+b_len+OVERFLOW
using namespace std;
int getCarry(int num) {
int carry = 0;
if(num>=10) {
while(num!=0) {
carry = num %10;
num = num/10;
}
}
else carry = 0;
return carry;
}
int num(char a) {
return int(a)-48;
}
string mult(string a, string b) {
string ret;
int a_len = a.length();
int b_len = b.length();
int mat[ROW][COL];
for(int i =0; i<ROW; ++i) {
for(int j=0; j<COL; ++j) {
mat[i][j] = 0;
}
}
int carry=0, n,x=a_len-1,y=b_len-1;
for(int i=0; i<ROW; ++i) {
x=a_len-1;
carry = 0;
for(int j=(COL-1)-i; j>=0; --j) {
if((x>=0)&&(y>=0)) {
n = (num(a[x])*num(b[y]))+carry;
mat[i][j] = n%10;
carry = getCarry(n);
}
else if((x>=-1)&&(y>=-1)) mat[i][j] = carry;
x=x-1;
}
y=y-1;
}
carry = 0;
int sum_arr[COL];
for(int i =0; i<COL; ++i) sum_arr[i] = 0;
for(int i=0; i<ROW; ++i) {
for(int j=COL-1; j>=0; --j) {
sum_arr[j] += (mat[i][j]);
}
}
int temp;
for(int i=COL-1; i>=0; --i) {
sum_arr[i] += carry;
temp = sum_arr[i];
sum_arr[i] = sum_arr[i]%10;
carry = getCarry(temp);
}
for(int i=0; i<COL; ++i) {
ret.push_back(char(sum_arr[i]+48));
}
while(ret[0]=='0'){
ret = ret.substr(1,ret.length()-1);
}
return ret;
}
void printhuge(string a) {
cout<<"\n";
for(string::iterator i = a.begin(); i!=a.end(); ++i) {
cout<<*i;
}
}
int main() {
string a,b;
cin>>a>>b;
printhuge(mult(a,b));
return 0;
}
All is working fine, but I need to use char[] instead of "string" . I know it's silly but I have to use that format necessary. So - how can I convert the code to work with char[] definition ?
Any ideas is greatly appreciated, Thanks :)
Provided you don't need to modify the C string (the char array), i. e. it can be const char[] or const char *, use the c_str() method of std::string:
const char *c_string = str.c_str();
Edit: so your problem is that you should not use std::string at all. Well, in this case, this is how you can replace C++ strings with C strings:
C strings are 0-terminated arrays of char (or const char). As usually, in certain conditions, they decay into pointers.
You can get the length of a C string using the strlen() function in <string.h>.
To append strings to each other, use the strcat() or strncat() functions. Beware of buffer sizes and the extra space for the terminating NUL character!
etc.
Call std::string::c_str() on your string objects.
Just make sure the buffer isn't modifed by the functions.
Edit
Or, if you need to accept a char[], just create a string out of it.