Passing array of size 9 and becomes size 1 - c++

simple call by reference
void foo(int* A)
{
// ...
}
void main()
{
int A[] = {1,1,1,1,1,1,1,1,1};
foo(A);
}
not sure why but it is lessening the size of the array and losing/leaking information on the array....

You're passing a pointer to the first element of an array. Create your function with the prototype
void foo(int* A, int size);
You will still be able to access A[0...size-1] like normal.

You should totally drop C-style arrays and use std::array instead. Just compare this (which is the solution to your problem):
void foo(int* A, std::size_t size) {
// ...
}
int main() {
int A[] = {1,1,1,1,1,1,1,1,1};
foo(A, (sizeof(A) / sizeof(int)));
}
to:
template<std::size_t Size>
void foo(const std::array<int, Size>& array) {
// ...
}
int main() {
std::array<int, 9> A {{ 1, 1, 1, 1, 1, 1, 1, 1, 1 }};
foo(A);
}
Ain't it beautiful? Or just take a look at how gorgeous it is with std::vector:
void foo(const std::vector<int>& vector) {
// vector.size() is the size
}
int main() {
std::vector<int> A = { 1, 1, 1, 1, 1, 1, 1, 1, 1 };
foo(A);
}
And if you really want foo to be a generic algorithm, I'll just blow your mind with iterators:
template<class Iterator>
void foo(Iterator begin, Iterator end) {
// ...
}
int main() {
std::array<int, 9> A {{ 1, 1, 1, 1, 1, 1, 1, 1, 1 }};
std::vector<int> B = { 1, 1, 1, 1, 1, 1, 1, 1, 1 };
foo(A.begin(), A.end()); // not a single problem
foo(B.begin(), B.end()); // was given that day
}
C++ has an amazing (arguably) standard library and an amazing type system (if you don't overlook C legacy "features", like void*): use them.

not sure why but it is lessening the size of the array and losing/leaking information on the array....
In foo(), sizeof(A) == 8 not because it is "leaking" information, but because 8 is the size of the pointer of type int*. This is true regardless of how many integers A was initialized with in main().
This may shine some light on what is happening:
#include<iostream>
using namespace std;
void foo(int* A)
{
cout << "foo: " << sizeof(A) << endl; // 8
}
void bar(int A[])
{
cout << "bar: " << sizeof(A) << endl; // still 8
}
int main()
{
int A[] = {1,1,1,1,1,1,1,1,1};
cout << "main: " << sizeof(A) << endl; // 36 (=4*9)
foo(A);
bar(A);
return 0;
}
Output:
main: 36
foo: 8
bar: 8
In main, sizeof "knows" the size of A[] - it is sizeof(int) * length = 4 * 9 = 36. This information is lost when A[] is cast to a pointer A* in foo.
What if we pass in A as bar(int A[]) instead. Will that retain the array length? No! In that case, sizeof(A) is still 8, the size of the pointer. Only in main does the compiler retain the information of array size of A.
If you want your functions to know the size of the array, use the std::vector<int> template, or pass in the size separately.
Here's another discussion on this: When a function has a specific-size array parameter, why is it replaced with a pointer?

The correct way to pass array by reference is
void foo(int (&A) [9])
{
// sizeof(A) == sizeof(int) * 9
}
the generic way is so:
template <std::size_t N>
void foo(int (&A) [N])
{
// sizeof(A) == sizeof(int) * N
}
You may use std::array (C++11 required) which has a syntax more intuitive
template <std::size_t N>
void foo(std::array<int, N> &A)
{
// A.size() == N
}

Related

Is there a way to use an array passed as parameter on std::begin or std::end?

I keep getting a compilation error if I use an array passed as parameter to a method on std::begin or std::end such as this:
#include <iostream>
#include <algorithm>
using namespace std;
class Test
{
public:
static bool exists(int ints[], int size, int k)
{
if (std::find(std::begin(ints), std::end(ints), k) != std::end(ints)) {
return true;
}
return false;
}
};
I tried casting it to &int[0] but it will still not compile.
The parameter ints is not an array, so you aren't passing an array into std::begin / std::end in the example. A function parameter is never an array in C++. When you declare a function array to be an array such as in your example, that parameter is adjusted to be a pointer to the element of such array. In your case, the type of the parameter ints has been adjusted to be a pointer to int i.e. int*, and you cannot pass a pointer into std::begin / std::end, as the error message surely explains.
You have passed the size as another parameter, so you could instead use:
std::find(ints, ints + size, k)
A more modern API design is to wrap the pointer and the size into a single class. The C++20 standard library comes with such class template: std::span. It also has convenient range algorithms that are quite convenient:
static bool exists(std::span<const int> ints, int k)
{
if (std::ranges::find(ints, k) != std::end(ints)) {
Even moreso, C++20 standard library has a function template that makes your function unnecessary:
std::ranges::contains(some_array, k);
Use std::span.
try this:
#include <algorithm>
#include <iostream>
#include <span>
bool exists(std::span<int> span, int needle) {
return std::find(span.begin(), span.end(), needle) != span.end();
}
int main() {
int arr[] = {0, 1, 2, 3, 4};
bool ok = exists(arr, 3);
if (ok) {
std::cout << "ok" << '\n';
} else {
std::cout << "not ok" << '\n';
}
return 0;
}
Here is a working example.
#include <iostream>
#include <vector>
bool exists(int x[], const int size, const int k)
{
std::vector<int> v(x, x + size);
if (std::find( v.begin(), v.end(), k) != v.end()) {
return true;
}
return false;
}
int main()
{
int const sz = 10;
int arrayi[sz] = { 1, 2, 3,4 ,5 ,6 ,7 , 8, 9, 0 };
if (exists(arrayi, sz, 4))
std::cout << "exist" << std::endl;
else
std::cout << "it does not" << std::endl;
}

How to directly specify some values as an argument in C++ instead of specifying an array name or a pointer to an array

Can I write a function in C++ to accept an array of values like this:
void someFunction(/*the parameter for array*/){
//do something
}
someFunction({ 1, 2, 3 });
There are various ways of doing this.
Method 1
Using initializer_list as parameter type.
void someFunction(std::initializer_list<int> init){
}
int main()
{
someFunction({ 1, 2, 3 });
}
Method 2
Using std::vector<int> as parameter type.
void someFunction(const std::vector<int> &init){
}
int main()
{
someFunction({ 1, 2, 3 });
}
You could get inspiration from e.g. std::min and use std::initializer_list
void someFunction(std::initializer_list<int> ints) {
for (int i : ints)
{
std::cout << i << '\n';
}
}
Yes you can.
One option is to use std::vector, and in your specific case std::vector<int> const& for the parameter of someFunction:
#include <iostream>
#include <vector>
void someFunction(std::vector<int> const & a)
{
for (int i : a)
{
std::cout << i << ", ";
}
std::cout << std::endl;
}
int main()
{
someFunction({ 1, 2, 3 });
return 0;
}
Output:
1, 2, 3,

why the array casted from void pointer* cannot iterate the for loop?

I made an array with 5 integer elements, and passed it to the test method which takes its parameter with the void pointer.
After casting it to the integer array, I tried to looping the array with for statement.
But it does not work. Why is this happening?
#include <iostream>
using namespace std;
void test(void* arr){
int* arr2 = static_cast<int*>(arr);
for(int num:arr2){
cout << num << endl;
}
}
int main(){
int arr[5] = {1,2,3,4,5};
test(arr);
}
Array decays to a pointer and loses all size information in the function. Here's a solution with templates:
#include <iostream>
template <typename T>
void test(T const& arr) {
for (auto const& num : arr) {
std::cout << num << '\n';
}
}
int main() {
int arr[5] = {1, 2, 3, 4, 5};
test(arr);
}
You can't use range-based for to iterate over an array of unknown bound or "over" a pointer. A compiler doesn't know where to stop.
Assuming that for some reason arr parameter is fixed to be void*, you can pass the size explicitly:
void test(void* arr, std::size_t size) {
int* arr2 = static_cast<int*>(arr);
while (size-- > 0)
std::cout << *arr2++ << std::endl;
}
int main() {
int arr[5] = {1, 2, 3, 4, 5};
test(arr, 5);
}
But this is an example of a bad code. Don't do it unless you have a good reason.
If you want to use a range-based for loop, in C++20 you'll be able to use use std::span:
void test(void* arr, std::size_t size) {
int* arr2 = static_cast<int*>(arr);
std::span span(arr2, size);
for (int num : span)
std::cout << num << std::endl;
}
Before that you can use a self-made workaround:
template<typename T>
class my_span {
public:
my_span(T* first, std::size_t size) :
first_(first), size_(size) {}
T* begin() const {
return first_;
}
T* end() const {
return first_ + size_;
}
private:
T* const first_;
const std::size_t size_;
};
void test(void* arr, std::size_t size) {
int* arr2 = static_cast<int*>(arr);
my_span span(arr2, size);
for (int num : span)
std::cout << num << std::endl;
}
arr and arr2 are pointers, not arrays. The length of the array they point to is unknown to test, thus the range-based for does not iterate over the array.

Primitive array vs. Array template in C++

I got this question from the cracking the coding interview book. I was able to write this method in python and java. But when I tried to write it in c++, the compiler starts yelling at me. I think the problem is that in the main function, I had a array instantiated by a template but the function is taking in a primitive array. How should I instantiate a primitive array?
// Given a sorted array of positive integers with an empty spot (zero) at the
// end, insert an element in sorted order.
bool sortSortedArray(size_t arrInt[], size_t x)
{
size_t indexArr{0};
size_t insertNum{x};
while (x != 0) {
if (x < arrInt[indexArr]) {
size_t swapVal = arrInt[indexArr];
arrInt[indexArr];
insertNum = swapVal;
++indexArr;
}
}
return true;
}
// Test the sortSortedArray function.
int main()
{
array<size_t, 5> testArr{1, 4, 5, 8, 0};
if (sortSortedArray(testArr, 3)) {
return 0;
}
}
Either make testArr a primitive array:
int testArr[] = {1, 4, 5, 8, 0};
or call data() to get the underlying array:
if (sortSortedArray(testArr.data(), 3)) {
#include <cstddef>
#include <array>
#include <iostream>
// this is a function template because each std::array<> parameter set creates a
// a type and we need a function for each type (we know std::size_t is the element
// type so this is only parameterized on the size)
template<size_t ArrSize>
void sortSortedArray(
std::array<std::size_t, ArrSize>& arr,
const std::size_t insertNum)
{
// last position is known to be "empty"
arr[arr.size() - 1] = insertNum;
// swap value in last position leftwards until value to the left is less
auto pos = arr.size() - 1;
if (pos == 0)
return;
while (arr[pos - 1] > arr[pos])
{
const auto tmp = arr[pos - 1];
arr[pos - 1] = arr[pos];
arr[pos] = tmp;
--pos;
if (pos == 0)
return;
}
}
template<typename T, size_t N>
void printArray(const std::array<T, N>& r)
{
for (const auto i : r)
{
std::cout << i << " ";
}
std::cout << '\n';
}
int main()
{
std::array<std::size_t, 5> testArr{{1, 4, 5, 8, 0}};
printArray(testArr);
sortSortedArray(testArr, 3);
printArray(testArr);
}

Templated static member functions in C++

I've written a simple test program to try to learn how to use template static member functions in C++. The code compiles, but doesn't work right (prints out some garbage). I guess I'm using the right syntax. I've read this or this and some other stuff but still don't know what I'm doing wrong. The code below:
#include <iostream>
using namespace std;
class Util {
public:
Util();
virtual ~Util();
template <typename T> static void printTab(T tab[]);
};
template <typename T>
void Util::printTab(T tab[]) {
for (unsigned int i=0; i<sizeof(tab)/sizeof(tab[0]); i++) {
cout << tab[0] << " ";
}
cout << endl;
}
int main() {
float tabFloat[5] {1, 2, 3, 4, 5};
unsigned char tabChar[3] {1, 2, 3};
Util::printTab(tabFloat);
Util::printTab(tabChar);
return 0;
}
Any hints appreciated.
You need to pass the size as another template argument :
#include <iostream>
using namespace std;
class Util {
public:
Util();
virtual ~Util();
template <typename T,int N> static void printTab(T (&tab)[N])
{
for (int i=0; i<N; i++) {
cout << tab[i] << " ";
}
cout << endl;
}
};
int main() {
float tabFloat[5] {1, 2, 3, 4, 5};
unsigned char tabChar[3] {1, 2, 3};
Util::printTab(tabFloat);
Util::printTab(tabChar);
}
sizeof(tab) is the size of a T*, it will not return the size of the whole array. You need to pass that in yourself as another argument to the function. See here for an explanation and another potential workaround: When a function has a specific-size array parameter, why is it replaced with a pointer?
Note that the second printTab will not output readable characters. If you want to see something printed out, try with:
unsigned char tabChar[3] {'1', '2', '3'};
How about trying, you need to send the size of the array when calling a function:
#include <iostream>
using namespace std;
class Util {
public:
Util();
virtual ~Util();
template <typename T> static void printTab(T tab[], size_t sz);
};
template <typename T>
void Util::printTab(T tab[], size_t sz) {
for (unsigned int i=0; i<sz; i++) {
cout << tab[i] << " ";
}
cout << endl;
}
int main() {
float tabFloat[5] {1, 2, 3, 4, 5};
unsigned char tabChar[3] {1, 2, 3};
Util::printTab(tabFloat, sizeof(tabFloat)/sizeof(float));
Util::printTab(tabChar, sizeof(tabChar)/sizeof(char));
return 0;
}
I'd pass the number of elements of T as a function argument or use a STD container such as a Vector.
Your for loop is just printing the first element tab[0] not tab[i]
Your initialization of tabFloat and tabChar are missing =
float tabFloat[5] {1, 2, 3, 4, 5};
unsigned char tabChar[3] {1, 2, 3};
(also I'd use 65, 66, 67 instead of 1,2,3 for console readability in your testing)
float tabFloat[5] = {1, 2, 3, 4, 5};
unsigned char tabChar[3] = { 65, 66, 67};