I need to implement a small function which does the byte swapping for an array with given length.
void myFunc (MYTYPE arrayPointer, const int& length)
{
unsigned int* tmp = (unsigned int*) arrayPointer;
for (int j=0; j < length; j = j + 4)
{
*tmp = htonl (*(tmp));
tmp++;
}
}
I don't want the user to do typecasting while using the function. I think I have two options left:
1. Replace MYTYPE with (void*)
2. Use templates.
Which option is better or preferable? Is there any better way than these two?
Templates, obviously. You're going to need an enable_if on sizeof(T)==4.
Related
I'm currently learning arrays and how they work. I'm given the following function that is used to find the maximum elements in three different arrays, A, B and C:
void findMax(int A[], int B[], int C[])
{
int maxA = A[0], maxB = B[0], maxC = C[0];
for (int i = 1; i < MAX_LEN; i++)
{
if(maxA < A[i]) maxA = A[i];
if(maxB < B[i]) maxB = B[i];
if(maxC < C[i]) maxC = C[i];
}
}
My goal is to figure out how to return all three values (maxA, maxB, maxC) without adding extra arguments. I'm allowed to change the return type and I can write code outside the function.
My first thought was to change void into int and create a new array that has those three max values. However, I think I need pointers to return arrays and we haven't learned that yet.
There are a few ways to approach this.
The Traditional Approach (Arrays)
The easiest way is to make the function return an int[]. This gives back all of the values easily and in a very concise format. However, the int[] type cannot guarantee that its size is 3 or that it contains what you claim it contains, so this is not a very type-friendly approach.
The OO Approach (Structs)
Most JAVA enthusiasts will tell you to make a struct or a class that encapsulates the idea, such as this.
struct MaxVals {
int maxA;
int maxB;
int maxC;
// Possibly a constructor here
};
This is still a very memory-efficient solution and is much cleaner than the array approach. It also has the benefit of being more type-safe; you can't make a MaxVals with four or two ints now; it's guaranteed at compile-time to have 3. However, this is bulky. It requires you to define a new type, completely outside of your function, that will only ever be used in this one case.
The Modern Approach (Tuples)
This is a new feature of C++, adapted from Python and Haskell, so it's only available in C++11, which has limited support across compilers. Tuples are a new data structure in the tuple header which can guarantee heterogeneous, fixed-size data structures of any types you specify at compile-time. You would set your return type to std::tuple<int, int, int> and initialize the structure with std::make_tuple(maxA, maxB, maxC).
This approach has the same memory advantages and guarantees as the struct approach but without all the overhead and boilerplate of declaring a one-use type. This would be the ideal approach for a problem like this, if your compiler supports it.
There are two things, you can do:
The first is declare maxA, maxB, maxC out side the function (globally). Then access them in your findMax function and main function.
int maxA, maxB, maxC;
void findMax(int A[], int B[], int C[])
{
maxA = A[0], maxB = B[0], maxC = C[0];
for (int i = 1; i < MAX_LEN; i++)
{
if(maxA < A[i]) maxA = A[i];
if(maxB < B[i]) maxB = B[i];
if(maxC < C[i]) maxC = C[i];
}
}
The second is use structure.
struct node
{
int maxA,maxB,maxC;
};
struct node findMax(int A[], int B[], int C[])
{
struct node Max_node;
Max_node.maxA = A[0], Max_node.maxB = B[0], Max_node.maxC = C[0];
for (int i = 1; i < MAX_LEN; i++)
{
if(Max_node.maxA < A[i]) Max_node.maxA = A[i];
if(Max_node.maxB < B[i]) Max_node.maxB = B[i];
if(Max_node.maxC < C[i]) Max_node.maxC = C[i];
}
return Max_node;
}
P.S: you also could use pointers, but as you said you are unfamiliar with them, I used other ways.
#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.
The function cannot initialize an array because sizeof() returns bytes of an int pointer
not the size the memory pointed by myArray.
void assignArray(int *myArray)
{
for(int k = 0; k < sizeof(myArray); ++k)
{
myArray[k] = k;
}
}
Are there other problems ?
Thanks
Well no, there are no other problems. The problem you stated is the only thing stopping you from initialising the array.
Typically, this is solved by simply passing the size along with the pointer:
void assignArray(int* myArray, std::size_t mySize)
{
for (std::size_t k = 0; k < mySize; ++k)
myArray[k] = k;
}
Note that I've used std::size_t for the size because that is the standard type for storing sizes (it will be 8 bytes of 64-bit machines, whereas int usually isn't).
In some cases, if the size is known statically, then you can use a template:
template <std::size_t Size>
void assignArray(int (&myArray)[Size])
{
for (std::size_t k = 0; k < Size; ++k)
myArray[k] = k;
}
However, this only works with arrays, not pointers to allocated arrays.
int array1[1000];
int* array2 = new int[1000];
assignArray(array1); // works
assignArray(array2); // error
I don't see other problems. However, you probably wanted this:
template<int sz>
void assignArray(int (&myArray)[sz])
{
for(int k = 0; k < sz; ++k)
{
myArray[k] = k;
}
}
Unless, of course, even the compiler doens't know how big it is at compile time. In which case you have to pass a size explicitly.
void assignArray(int* myArray, size_t sz)
{
for(int k = 0; k < sz; ++k)
{
myArray[k] = k;
}
}
If you don't know the size, you have a design error.
http://codepad.org/Sj2D6uWz
There are two types of arrays you should be able to distinguish. One looks like this:
type name[count];
This array is of type type[count] which is a different type for each count. Although it is convertable to type *, it is different. One difference is that sizeof(name) gives you count*sizeof(type)
The other type of array looks like this:
type *name;
Which is basically just a pointer that you could initialize with an array for example with malloc or new. The type of this variable is type * and as you can see, there are no count informations in the type. Therefore, sizeof(name) gives you the size of a pointer in your computer, for example 4 or 8 bytes.
Why are these two sizeofs different, you ask? Because sizeof is evaluated at compile time. Consider the following code:
int n;
cin >> n;
type *name = new type[n];
Now, when you say sizeof(name), the compiler can't know the possible future value of n. Therefore, it can't compute sizeof(name) as the real size of the array. Besides, the name pointer might not even point to an array!
What should you do, you ask? Simple. Keep the size of the array in a variable and drag it around where ever you take the array. So in your case it would be like this:
void assignArray(int *myArray, int size)
{
for(int k = 0; k < size; ++k)
{
myArray[k] = k;
}
}
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
why isnt it legal to convert (pointer to pointer to non-const) to a (pointer to pointer to a const)
Hi I have the following code, but cannot wrap my head around why this doesn't work - I get an error saying "cannot convert from int** to const int**". However, if I change the first argument of printValues to be "const int *const * myArray", it all works fine. I know I probably shouldn't be using the one below anyway, but I don't understand why it doesn't compile at all. Can you not have a pointer to a pointer to a constant integer without declaring it constant in main()?
#include <iostream>
int printValues(const int ** myArray, const long nRows, const long nCols)
{
for (long iRow = 0; iRow < nRows; iRow++)
{
for (long iCol = 0; iCol < nCols; iCol++)
{
std::cout << myArray[iRow][iCol] << " ";
}
std::cout << "\n";
}
return 0;
}
int main()
{
const long nRows = 5;
const long nCols = 8;
int** myArray = new int* [nRows];
for (long iRow = 0; iRow < nRows; iRow++)
{
myArray[iRow] = new int [nCols];
}
for (long iRow = 0; iRow < nRows; iRow++)
{
for (long iCol = 0; iCol < nCols; iCol++)
{
myArray[iRow][iCol] = 1;
}
}
printValues(myArray, nRows, nCols);
return 0;
}
int ** is: "a pointer to a pointer to an integer".
const int ** is: "a pointer to a pointer to a constant integer".
A far-fetched analogy:
a note that describes the location of another note that describes the location of a jar
a note that describes the location of another note that describes the location of a closed jar
You can only put a cookie inside a jar that is not closed.
Now, think of replacing the second note with a photocopy of the first note. Do you have any guarantee that the ultimate jar that this note points to will be closed and cannot accept any cookies? The use of const is a contract and you cannot meet this contract by going through the indirection of two references.
Basically, this is because it's possible via changing the level of indirection and other valid, non-const-violating semantics that you can work around the const if it's only on the top level. You have to add const on more than one level for the const to be actually safe.
Edit:
You are violating const-correctness. By saying you want a pointer-to-a-pointer, you are setting yourself up by allowing the original const object to be modified. Const is a contract. By allowing this to happen without a cast, you are setting yourself up to allow a const object to be modified later on.
Can you tell me what's wrong with my method? I ends up putting the same thing everywhre and it's actually not sorting.
void sortArrays(){
int i, j;
for(i=0; i<counter; i++){
for( j=0; j<i; j++){
if( strcmp(title_arr[i], title_arr[j]) < 0){
char* title_temp = title_arr[i];
title_arr[j] = title_temp;
}
}
}
This:
char* title_temp = title_arr[i];
title_arr[j] = title_temp;
Is equivalent to:
title_arr[j] = title_arr[i];
You never swap them, you just copy one to the other. You should add this line:
title_arr[i] = title_arr[j];
In between the two. That way, you'll overwrite [i] with [j], but _temp still holds the old value of [i], so you can copy that value into [j], thus swapping them.
I suppose it's also a time for a lesson on algorithms. Your algorithm is known as a "bubble sort" algorithm. It is known for it's simplicity, but in a realistic setting it is known for it's inefficiency (the technical term is "teh sux", and the real technical term is O(n^2) ("N squared") performance). Some more common (and more efficient) algorithms include Quicksort, merge sort, and Heapsort, among many others. For more about measuring algorithmic scalability, see the article on Big Oh notation.*
But, as vava pointed out in a comment, unless your assignment is to write your own sorting function, you're going to get better performance with qsort (in C) or std::sort (in C++).
int mystrsort(const void *a, const void *b)
{
return strcmp(*(const char **)a, *(const char **)b);
}
// later:
qsort(title_arr, sizeof title_arr / sizeof(char *), sizeof(char *), mystrsort);
I'm not going to stab at std::sort, but it's going to work about the same (perhaps easier).**
*Note that anyone who likes is free to change these Wikipedia links to Stack Overflow links. It would be better to link to SO, I just linked to Wikipedia because I knew how to find the info I needed faster.
**Note that anyone who likes is free to add a std::sort example. I'm just not sufficiently familiar with C++.
You didn't swap properly, that's why it didn't work.
#include <iostream>
#include <algorithm>
int const counter = 4;
char * title_arr[counter] = {
"d", "c", "b", "a"
};
void sortArrays(){
for(int i = 0; i < counter; i++){
for(int j = 0; j < i; j++){
if(strcmp(title_arr[i], title_arr[j]) < 0){
char* title_temp = title_arr[i];
title_arr[i] = title_arr[j];
title_arr[j] = title_temp;
//you wouldn't have made that stupid mistake this way.
//std::swap(title_arr[i], title_arr[j]);
}
}
}
}
int compare(void const * a, void const * b) {
return strcmp(static_cast<char const *>(a), static_cast<char const *>(b));
}
struct StringLess : public std::binary_function<char const *, char const *, bool> {
bool operator() (char const * a, char const * b) const {
return strcmp(a, b) < 0;
}
};
int main(int argc, char * argv[])
{
sortArrays();
//those ones better
// qsort(title_arr, counter, sizeof(char *), compare);
// std::sort(title_arr, title_arr + counter, StringLess());
for (int i = 0; i < counter; i++) {
std::cout << title_arr[i] << ", ";
}
return 0;
}
Bad coding style:
1. Don't use global variables. It's better to pass your array and length as arguments into sort function. Why? Your function is not reusable. What if you will need to sort another array? Yes, you will need to write another sort function...
2. More advanced tip: use emulation of higher-order function. What if you will need to sort not only characters? Integer, floats, strings or your own types. In this case you can also pass compare() function into your sort function which can compare objects of your array.