This is a routine that I believe is for C. I copied it (legally) out a book and am trying to get it to compile and run in visual studio 2008. I would like to keep it as a C++ program. Lots of programming experience in IBM mainframe assembler but none in C++. Your help is greatly appreciated. I think just a couple of simple changes but I have read tutorials and beat on this for hours - getting nowhere. Getting a lot (4) of error C2440 '=' : cannot convert form 'void*' to to 'int*' errors in statements past the reedsolomon function: Thanks so much! Program follows:
#include <iostream>
using namespace std;
int wd[50] = {131,153,175,231,5,184,89,239,149,29,181,153,175,191,153,175,191,159,231,3,127,44,12,164,59,209,104,254,150,45};
int nd = 30, nc=20, i, j, k, *log, *alog, *c, gf=256, pp=301;
/* The following is routine which calculates the error correction codewords
for a given data codeword string of length "nd", stored as an integer array wd[].
The function ReedSolomon()first generates log and antilog tables for the Galois
Field of size "gf" (in the case of ECC 200, 28) with prime modulus "pp"
(in the case of ECC 200, 301), then uses them in the function prod(), first to
calculate coefficients of the generator polynomial of order "nc" and then to
calculate "nc" additional check codewords which are appended to the data in wd[].*/
/* "prod(x,y,log,alog,gf)" returns the product "x" times "y" */
int prod(int x, int y, int *log, int *alog, int gf)
{if (!x || !y)
return 0;
else
return alog[(log[x] + log[y]) % (gf-1)];
}
/* "ReedSolomon(wd,nd,nc,gf.pp)" takes "nd" data codeword values in wd[] */
/* and adds on "nc" check codewords, all within GF(gf) where "gf" is a */
/* power of 2 and "pp" is the value of its prime modulus polynomial */
void ReedSolomon(int *wd, int nd, int nc, int gf, int pp)
{int i, j, k, *log,*alog,*c;
/* allocate, then generate the log & antilog arrays: */
log = malloc(sizeof(int) * gf);
alog = malloc(sizeof(int) * gf);
log[0] = 1-gf; alog[0] = 1;
for (i = 1; i < gf; i++)
{alog[i] = alog[i-1] * 2;
if (alog[i] >= gf) alog[i] ^= pp;
log[alog[i]] = i;
}
/* allocate, then generate the generator polynomial coefficients: */
c = malloc(sizeof(int) * (nc+1));
for (i=1; i<=nc; i++) c[i] = 0; c[0] = 1;
for (i=1; i<=nc; i++)
{c[i] = c[i-1];
for (j=i-1; j>=1; j--)
{c[j] = c[j-1] ^ prod(c[j],alog[i],log,alog,gf);
}
c[0] = prod(c[0],alog[i],log,alog,gf);
}
/* clear, then generate "nc" checkwords in the array wd[] : */
for (i=nd; i<=(nd+nc); i++) wd[i] = 0;
for (i=0; i<nd; i++)
{k = wd[nd] ^ wd[i] ;
for (j=0; j<nc; j++)
{wd[nd+j] = wd[nd+j+1] ^ prod(k,c[nc-j-1],log, alog,gf);
}
}
free(c);
free(alog);
free(log);
return ();
}
int main ()
{reedsolomon (50,30,20,256,301);
for (i = 1; i < 51; i++)
{cout<< i; "="; wd[i];}
cout<<"HEY, you, I'm alive! Oh, and Hello World!\n";
cin.get();
return 1;
}
In C++, a void pointer can't be implicitly cast to a different pointer.
So instead of
int *pInt;
pInt = malloc(sizeof(int) * 5);
You need to say
int *pInt;
pInt = (int *) malloc(sizeof(int) * 5);
or preferably
int *pInt = new int[5];
(with a matching delete[] instead of free), or preferably preferably use a vector if it's intended to be dynamic.
At the beginning of the program type: #include <cstdlib> . If you do not include this library, then malloc will not work. In C++, void* to int* is not an automatic conversion, in lines: 31 32 and 40 you need to cast to int* e.g: log = (int *)malloc(sizeof(int) * gf);
At main funcion, line 63 you're calling the function as reedsolomon, it should be ReedSolomon, the way you declared it.
Also, in "void ReedSolomon(int *wd, int nd, int nc, int gf, int pp)" when you call the function in the main, you say ReedSolomon (50,30,20,256,301); so you are asigning an int value to a pointer to int, that's a type clash. I'm not sure what it is you want to do with wd.
Next time, please post the errors from the compiler so people dont have to compile the code themselves to check and see whats wrong.
Also a good technique which will save you a lot of time is to do a google search on the error the compiler gives you (it is very likely somebody already had that same mistake), and also read a C++ book to get acquainted with the language.
Cheers!
C++ requires that you cast the return value of malloc to whatever type of pointer you're assigning it to. So e.g. log = malloc(sizeof(int) * gf); needs to become log = (int *) malloc(sizeof(int) * gf);.
You should type cast when assigning a pointer to the return of malloc.
Example:
log = reinterpret_cast<int*>(malloc(sizeof(int) * gf));
Related
I want to convert the following code from objective C to C++.
In the class myClass, I have this attribute:
float tab[dim1][dim2][dim3];
In an objective-C file, the multidimensional array is filled from a binary file:
NSData *dataTab=[NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"pathOfMyTab" ofType:#""]];
[dataTab getBytes:myClass -> tab length:[dataTab length]];
How could I translate this part into C++ ?
I am assuming that your file contains the byte-representation of the array. If this is the case, then to mimic the behaviour of your Objective-C code using only C++ (the only thing that makes this C++ is the reinterpret_cast<>, otherwise it is just straight C), you could use the following code. I have not added any error checking, but left some comments where you might want to perform some.
float tab[dim1][dim2][dim3];
CFBundleRef mainBundle = CFBundleGetMainBundle();
CFURLRef dataTabURL = CFBundleCopyResourceURL(mainBundle, CFSTR("pathOfMyTab"), NULL, NULL);
CFReadStreamRef stream = CFReadStreamCreateWithFile(NULL, dataTabURL); // check for NULL return value
CFReadStreamOpen(stream); // check for errors here
CFReadStreamRead(stream, reinterpret_cast<UInt8 *>(tab), sizeof tab); // check that this function returns the number of bytes you were expecting (sizeof tab)
CFReadStreamClose(stream);
// we own "stream" and "dataTabURL" because we obtained these through functions
// with "create" in the name, therefore we must relinquish ownership with CFRelease
CFRelease(stream);
CFRelease(dataTabURL); // ditto
If you already have the path available in a std::string, then you can use the following C++ code to mimic the behaviour of your Objective-C code:
// make sure to include this header
#include <fstream>
// ... then elsewhere in your .cpp file ...
float tab[dim1][dim2][dim3];
std::string path = "path/to/mytab"; // obtain from somewhere
std::ifstream input(path, std::ios::binary); // check that the file was successfully opened
input.read(reinterpret_cast<char *>(tab), sizeof tab); // check that input.gcount() is the number of bytes you expected
I believe in this case we have to use reinterpret_cast<> because the file contains the actual representation of the array (assuming it was previously written to the file in a similar manner).
You can use a hybrid approach, once you have the CFURLRef containing the path to the resource, you can obtain a file system representation of the URL using this function (providing a suitably sized output buffer to store the result), and from there you should be able to pass that to one of std::ifstream's constructors (although, you may need to cast to the appropriate type).
C++ doesn't support variable-length arrays (the size of arrays must be known at compile time). There is also no matrix type provided by the standard library, so if the dimensions of your table vary at run time, then you will need a completely separate approach to the one in my answer. You could consider serialising the output from Objective-C (using e.g. JSON or another format) such that the dimensions of the matrix are also written to the output, making it easier to parse the file in C++.
Take a look at fstream, fread and read, all read binary files, pick the approach that suits.
On my mind the simplest and fastest way is to use memcpy() to copy NSData' bytes into target array with same structure (dimensions) as a source one. See, for example:
https://github.com/Voldemarus/MultiDimensionalArrayDemo/tree/master
#import "DemoClass.h"
#define DIM1 3
#define DIM2 4
#define DIM3 2
#interface DemoClass() {
int src[DIM1][DIM2][DIM3]; // source (initial) array
int dst[DIM1][DIM2][DIM3]; // destination array
}
#end
#implementation DemoClass
- (instancetype) init
{
if (self = [super init]) {
for (int i = 0; i < DIM1; i++) {
for (int j = 0; j < DIM2; j++) {
for (int k = 0; k < DIM3; k++) {
int value = i*100 + j*10 + k;
src[i][j][k] = value;
}
}
}
}
return self;
}
int getIntFromArray(int *array, int i, int j, int k) {
int offset = j*DIM3 + i*DIM2*DIM3;
return array[offset];
}
void putIntToArray(int *array, int i, int j, int k, int value) {
int offset = j*DIM3 + i*DIM2*DIM3;
array[offset] = value;
}
- (void) run
{
// Step 1. Save array into NSData
NSInteger s = sizeof(int)*DIM1*DIM2*DIM3;
NSData *data = [[NSData alloc] initWithBytes:src length:s];
NSAssert(data, #"NSData should be created");
//Step2 - Create new array
int *bytes = (int *)[data bytes];
memcpy(dst,bytes,s);
// Step 3. Compare src and dst
for (int i = 0; i < DIM1; i++) {
for (int j = 0; j < DIM2; j++) {
for (int k = 0; k < DIM3; k++) {
int template = i*100 + j*10 + k;
int s = src[i][j][k];
int d = dst[i][j][k];
// NSLog(#"i %d j %d k %d -->s = %d d = %d",i,j,k,s,d);
NSAssert(s == template, #"Source array should have value from template");
NSAssert(d == s, #"Destination array should be identical to the source");
}
}
}
}
#end
float tab[dim1][dim2][dim3] looks like a three-dimensional array. The standard implementation is with three nested FOR loops.
So your C++ implementation can look like this:
read dim1, dim2, dim3 from somewhere, usually the first values in the file (for example 12 bytes, 4 bytes for each number)
read the rest of the file in three nested FOR loops
Something like:
for (size_t i = 0; i < dim1; ++i)
for (size_t j = 0; j < dim2; ++j)
for (size_t k = 0; k < dim3; ++k)
tab[i][j][k] = read_float_value(inputFile);
In Objective-C you can write the file in a similar way.
Here are some examples to get you started:
Three dimensional arrays of integers in C++
3D array C++ using int [] operator
Consider the following program that is supposed to do some stupid addition of doubles:
#include <iostream>
#include <vector>
#include <mpi.h>
void add(void* invec, void* inoutvec, int* len, MPI_Datatype*)
{
double* a = reinterpret_cast <double*> (inoutvec);
double* b = reinterpret_cast <double*> (invec);
for (int i = 0; i != *len; ++i)
{
a[i] += b[i];
}
}
int main(int argc, char* argv[])
{
MPI_Init(&argc, &argv);
std::vector<double> buffer = { 2.0, 3.0 };
MPI_Op operation;
MPI_Op_create(add, 1, &operation);
MPI_Datatype types[1];
MPI_Aint addresses[1];
int lengths[1];
int count = 1;
MPI_Get_address(buffer.data(), &addresses[0]);
lengths[0] = buffer.size();
types[0] = MPI_DOUBLE;
MPI_Datatype type;
MPI_Type_create_struct(count, lengths, addresses, types, &type);
MPI_Type_commit(&type);
MPI_Allreduce(MPI_IN_PLACE, MPI_BOTTOM, 1, type, operation, MPI_COMM_WORLD);
MPI_Type_free(&type);
MPI_Op_free(&operation);
MPI_Finalize();
std::cout << buffer[0] << " " << buffer[1] << "\n";
}
Because this is part of larger program where the data I want to send is 1) on the heap and 2) consists of different types I think I have to use a user-defined type.
Now something must be wrong here because the program crashes when run with mpirun -n 2 ./a.out. The backtrace from gdb is:
#0 __memcpy_sse2_unaligned () at ../sysdeps/x86_64/multiarch/memcpy-sse2-unaligned.S:158
#1 0x00007ffff65de460 in non_overlap_copy_content_same_ddt () from /usr/local/lib/libopen-pal.so.6
#2 0x00007ffff180a69b in ompi_coll_tuned_allreduce_intra_recursivedoubling () from /usr/local/lib/openmpi/mca_coll_tuned.so
#3 0x00007ffff793bb8b in PMPI_Allreduce () from /usr/local/lib/libmpi.so.1
#4 0x00000000004088b6 in main (argc=1, argv=0x7fffffffd708) at mpi_test.cpp:39
Line 39 is the MPI_Allreduce call. This is probably a dumb mistake, but after staring on it for hours I still don't see it. Does anyone spot the mistake? Thanks!
Edit: There is a bug in how Open MPI handles types with non-zero lower bounds (such as the one that you create when using absolute addresses) while performing in-place reduce-to-all. It seems to exist in all versions, including the development branch. The status can be tracked by following the issue on GitHub.
Your add operator is wrong as you fail to account for the datatype's lower bound. A proper solution would be something like:
void add(void* invec, void* inoutvec, int* len, MPI_Datatype* datatype)
{
MPI_Aint lb, extent;
MPI_Type_get_true_extent(*datatype, &lb, &extent);
double* a = reinterpret_cast <double*> (reinterpret_cast <char*>(inoutvec) + lb);
double* b = reinterpret_cast <double*> (reinterpret_cast <char*>(invec) + lb);
for (int i = 0; i != *len; ++i)
{
a[i] += b[i];
}
}
This will access the data correctly but is still wrong. *len will be 1 as that is what you pass to MPI_Allreduce but there are two doubles behind each element. The correctly written operator will either use the type introspection mechanism to obtain the length of the block of doubles and multiply *len by it or simply hardcode the vector length to be two:
for (int i = 0; i < 2*(*len); i++)
{
a[i] += b[i];
}
For my programming project, I am supposed to write a program that sorts integers on a disk (i.e. offline sort). I am first supposed to generate some random integers, write all of them, and read two of those integers for swapping, and write them back to the disk, and repeat those steps until the numbers are sorted. I am able to generate random numbers just fine, and had no problem opening the file, but it crashes when an attempt is made to write to the file. Here is the fragment of the code for the program that I used to implement the sort, that contains the sorting algorithm, and the segment of the code that crashes my program:
void ReadAndWrite(int & rand_ints, int & pos_ints)
{
int rand_ints2 = 0;
GetNumber(pos_ints);
srand(time(0));
fstream finout;
finout.open(SORTFILE, ios::binary | ios::in | ios::out);
if (finout.is_open())
{
for (int i = 0; i < pos_ints; ++i)
{
rand_ints = rand() % 5;
finout.write(reinterpret_cast <char *>(rand_ints), sizeof(int) * 1);
}
for (int i = 0; i < pos_ints; ++i)
{
finout.seekg(ios::beg);
finout.read(reinterpret_cast <char *>(rand_ints), sizeof(int) * 2);
bubbleSort(&rand_ints, 2, sizeof(int), compare_ints);
finout.seekp(ios::app);
finout.write(reinterpret_cast <char *>(rand_ints), sizeof(int) * 2);
}
finout.close();
}
else
{
cout << "File not opened!" << endl;
}
}
void GetNumber(int & pos_ints)
{
cout << "Enter a positive number: ";
cin >> pos_ints;
}
void bubbleSort(void * base, size_t num, size_t width, int(*compar) (const void *, const void *))
{
bool done = false;//Allows us to enter loop first time
int hi = num - 1;//largest index is 1 less than the size of the array
while (!done)
{
done = true;//assume the list is sorted
for (int i = 0; i<hi; i++)
{
//pass thru the array up to 'hi'
//if (arr[i+1]<arr[i])
if (compar((void *)(((char *)base) + width*(i + 1)), (void *)(((char *)base) + width*(i))) < 0)
{
//if any pair are out of order
done = false;//the list is not sorted
//int temp = arr[i];//swap them
void * tempp = (void *) new char[width];
memcpy_s(tempp, width, (((char *)base) + width*(i)), width);
//arr[i] = arr[i+1];
memcpy_s((((char *)base) + width*(i)), width, ((char *)base) + width*(i + 1), width);
//arr[i+1]=temp;
memcpy_s(((char *)base) + width*(i + 1), width, tempp, width);
delete[] tempp;
}
}
hi--;//at the end of a pass, largest item in that pass is in proper place; no need to go this far next time
}
}
int compare_ints(const void * arg1, const void * arg2)
{
int return_value = 0;
if (*(int *)arg1 < *(int *)arg2)
return_value = -1;
else if (*(int *)arg1 > *(int *)arg2)
return_value = 1;
return return_value;
}
It crashes on the line of code finout.write(reinterpret_cast (rand_ints), sizeof(int) * 1); within the first for loop (line 52), with the following error: Exception thrown at 0x55916D16 (msvcp140d.dll) in ExternalSort.exe: 0xC0000005: Access violation reading location 0x00000001.
Is there a way to fix this error and make this sorting program work? Tried everything I could have possibly tried, and I can't see a line of my code to cause the program to crash or cause other problems.
Since rand_ints is of type int, you probably mean reinterpret_cast<char *>(&rand_ints) (note the &). Otherwise, you'll be making a pointer out of an integral value.
OTOH, trying to read two adjacent integers into the address of a single integer variable is very likely to cause problems.
Looking more deeply into your sorting algorithm, it seems to me that you attempted to generalize it for data elements of any size, and not just ints. However, it is still clearly array-oriented; if you wanted to deal with files, you probably have to pass the function either a filename or a fstream reference.
Also, unless you're required to use Bubble Sort, I'd strongly advise you against it, especially for on-disk sorting, unless you make sure your data set is very, very small (say, no more than a hundred numbers). For in-place sorting, I'd advise you to use Quick Sort.
How should an array of constant size:
const int m = 5, n = 3;
int arr[m][n];
be passed to a function in a way which is both C89 and C++-compatible?
void func(const int m, const int n, int arr[][n]) { }
isn't valid C++ (giving errors such as "A parameter is not allowed" and "Variable 'n' was not declared in this scope"), even though the size of arr is determinate at compile-time. (It is valid C, however.) #defineing m and n works but is not preferred due to scope issues. Passing a pointer to the first element of the array leads to ugly code in the function body.
Feel free to take a look at this FAQ for context.
In C++, you can pass an array to a function with full type information intact by utilizing a template and an array reference function argument:
template <unsigned M, unsigned N>
void func (int (&arr)[M][N]) {
//...
}
The function prototype you are using is using a C99 feature called VLA to provide a dynamic binding of the array dimension. This is not a C++ feature, although some C++ compilers will allow it as an extension to the C++ language.
The C-FAQ was written before C99 was ratified, so the variable length array feature was not yet a standard feature of C. With a modern C compiler with VLA support, the function prototype you provided works just fine.
There is another alternative to use if you have an older compiler for which VLA support is not available. That is to treat the 2-D array as a flattened 1-D array, and use manual calculations to index the correct integer:
void func(const int m, const int n, void *p) {
int *a = p;
int i, j;
for (i = 0; i < m; ++i) {
for (j = 0; j < n; ++j) {
printf(" %d", a[i*n + j]);
}
puts("");
}
}
Then you call func(m, n, arr). In side the function, the expression
a[i*n + j]
steps over n ints i times, then steps over j ints. Since each row is n ints long, the calculation returns the ith row and the jth column, which corresponds precisely to arr[i][j].
I have tried this code:
void func(const int m, const int n, int arr[][n])
{
printf("%d\n", arr[4][2]);
}
int main()
{
const int m = 5, n = 3;
int arr[m][n];
arr[4][2] = 10;
func(m, n, arr);
}
and this work with no warnings
Your array arr[m][n] is not constant. However you have constant variables M and N. You should also define the arr[m][n] as a constant and not just an int array.
You may want to consider dynamicaly allocating your array so that you can just pass the pointer address down.
const int m = 5, n = 3;
int i = 0;
int* *arr; //Pointer to an integer pointer (Note can also be int **arr or int** arr)
arr = malloc(sizeof(int*)*(m+1)); //I add one because I am assuming that 'm' does not account for the terminating null character. But if you do not need a terminating null then you can remove this and the perantheses around the 'm'.
for(i = 0; i < m; i++)
{
arr[i] = malloc(sizeof(int*)*(n+1)); //Same as before
}
The inital malloc() call allocates memory for an array of integer arrays or said in another way, it allocates a pointer to a series of other pointers. The for loop will allocate an integer array of 'm' size for each element of the original array or said another way it will allocate space for every pointer address pointed to by the original pointer address. I left out error checking in order to simplfy my example but here is the same example with error checking.
const int m = 5, n = 3;
int i = 0;
int* *arr = NULL;
if((arr = malloc(sizeof(int*)*(m+1))) == NULL)
{
perror("ERROR(1): Failed to allocate memory for the initial pointer address ");
return 1;
}
for(i = 0; i < m; i++)
{
if((arr = malloc(sizeof(int*)*(m+1))) == NULL)
{
perror("ERROR(2): Failed to allocate memory for a subsequent pointer address ");
return 2;
}
}
Now that you have dynamicaly allocated your array you can just pass the pointer address.
int* *arr in the following the way.
void fun(const int n, const int m, int* *arr) {}
Also you don't necessarily have to keep track of the size of your arrays if the sizes are constant and if you use null terminated arrays. You just have to malloc the array using the constant integer variable's actual value and then check for the terminating null byte when iterating threw the array.
int* *arr = NULL;
if((arr = malloc(sizeof(int*)*6)) == NULL)'m'+1 = 6;
{
perror("ERROR(1): Failed to allocate memory for the initial pointer address ");
return 1;
}
for(i = 0; i < m; i++)
{
if((arr = malloc(sizeof(int*)*4) == NULL)//'n'+1 = 4
{
perror("ERROR(2): Failed to allocate memory for a subsequent pointer address ");
return 2;
}
}
You can then display the entire two dimensional array in the following way. Note that '\000' is the octagonal value for a null byte(00000000).
int i, j;
for(i = 0; arr[i] != '\000'; i++)
{
for(j = 0; arr[i][j] != '\000'; j++)
{
printf("%i ", arr[i][j]); //Prints the current element of the current array
}
printf("\n"); //This just ends the line so that each of the arrays is printed on it's own line.
}
Of course the above mentioned loops would have the same result as the following.
int i, j;
int m = 5;
int n = 3;
for(i = 0; i < m; i++)
{
for(j = 0; i < n; j++)
{
printf("%i ", arr[i][j]); //Prints the current element of the current array
}
printf("\n"); //This just ends the line so that each of the arrays is printed on it's own line.
}
Which means, in most situations there is no need for keeping track of an array's size but there are situations in which it is necessary. For example if one your arrays could possible contain a null byte other than the terminating null byte. The new null byte would shorten the array's size to the index of the new null byte. If you have any questions or comments feel free to comment below or message me.
The problem here is the "missing" support for dynamic arrays in C++.
const int m = 5, n = 3;
int arr[m][n];
Works since m and n are compile time constant and accessible directly at the declaration of the array.
void func(const int m, const int n, int arr[][n]) { }
The compiler handles your function regardless of where it is called in first place.
Therefore n is unknown/variable and thus prohibited as a array dimensionality.
The following example won't work too because of the very same reason:
void foo (const int n)
{
int arr[n]; // error, n is const but not compile time constant
}
int main (void)
{
foo(4);
}
jxh answered what to do about it.
#include<stdio.h>
#include<conio.h>
unsigned * bin(unsigned n) {
unsigned a[16];
int i = 0, j = 0;
for (i = 0; i < 16; i++) {
a[i] = n & 0x1;
n = n >> 1;
}
return a;
}
void main() {
unsigned n = 5;
int i = 0;
unsigned * a = bin(n);
for (i = 15; i >= 0; i--) {
printf("%d\n", (*(a + i)));
}
getch();
}
Please help this binary conversion does not work. I'm trying to calculate x^n using binary conversion.
can anybode help??
You are returning a pointer to a local variable. This variable is stored on the stack, and will not be valid after the function returns.
Dereferencing this pointer will lead to undefined behavior.
The solution is to either make the variable static, or pass in the array as an argument to the function, or (as noted in a comment by James Kanze) use a type that copies the contents.
you can not return a local array defined in the function in this way.
The content of the array will be erased when the function finish the execution.
instead of using
unsigned a[16];
you can use the following:
unsigned *a =malloc(16 * (sizeof *a));
And do not forget in your main to free the memory allocated for a when the a array become useless in your program. you can free the array with:
free(a);
Actually, this is a typical case where using new (or malloc) is a pretty bad choice. However, as others have said, returning a pointer to a local array is bad.
Instead, pass in an array:
void bin(unsigned n, unsigned a[]) {
int i = 0;
for (i = 0; i < 16; i++) {
a[i] = n & 0x1;
n = n >> 1;
}
}
and in main:
unsigned a[16];
bin(n, a);
Now you have no need to allocate or return an array from bin.