Like following code:
#include <iostream>
#include <string>
#define BUF_LEN_HEAP 32
#define BUF_LEN_STACK 64
int getBufLen(const char *buf)
{
//...
}
void foo(const char *buf)
{
int len = getBufLen(buf);
//memcpy(new_buf, buf, len);
//...
}
int main()
{
char buf_stack[BUF_LEN_STACK];
char *buf_heap = new char[BUF_LEN_HEAP];
std::string str("abcdef");
foo(buf_stack);
foo(buf_heap);
foo(str.c_str());
delete [] buf_heap;
return 0;
}
If get length of buffer very difficult pass argument to the functions.
Is there lower-level method to get length of buffer whatever the buffer allocated on stack or heap?
No, there is no way to get the size of an array outside of the method that declared it, and only if the array was declared with a static length (known at compile time).
The usual way to handle this is to pass both a pointer and a size to any function writing to the buffer, just as memcpy does.
With c++ there's always the better option to use a std::vector instead of a plain array. The std::vector carries all needed information within one object that's easy to pass around.
Related
I am writing a function which requires an array to be created at runtime. The array will be of small size so I am not worried about unsafe code, however, I want to write 'proper' code. As such I am considering three alternatives:
char array[len];
char array = new char(len);
std::vector array(len);
Using Compiler Explorer to compare them with -O3.
The results were as such:
12 instructions, 0 calls to new
21 instructions, 1 call to new
118 instructions, 2+ calls to new
Am I missing an optimisation for std::vector<> or is the 'proper' c++ way slower or have I entirely missed a way of coding this?
edit: I forgot to delete the heap-allocated array
Test code:
code 1:
#include <string.h>
void populate_array(char* arr);
int compute_result(char* arr);
int str_to_arr(const char* str)
{
auto len = strlen(str);
char array[len];
populate_array(array);
return compute_result(array);
}
code 2:
#include <string.h>
void populate_array(char* arr);
int compute_result(char* arr);
int str_to_arr(const char* str)
{
auto len = strlen(str);
char* array = new char[len];
populate_array(array);
auto result = compute_result(array);
delete[] array;
return result;
}
code 3:
#include <string.h>
#include <vector>
void populate_array(std::vector<char> arr);
int compute_result(std::vector<char> arr);
int str_to_arr(const char* str)
{
auto len = strlen(str);
std::vector<char> array(len);
populate_array(array);
return compute_result(array);
}
There are a few issues in the code, that may be leading you astray in the comparison.
new char(len) allocates a single char, initialized with the value len. You'd be after new char[len] to allocate len chars. There should be a matching delete [], too.
The std::vector<char> object is passed to populate_array by value, making a copy (and consequently not actually populating the array you want), and similarly for compute_result. These copies will engender new allocations. Passing by reference would be appropriate here.
Without using a custom allocator, std::vector will value-initialize all its elements. Effectively, it means that every element in this vector is set to zero. This is not performed by new char[len].
VLAs are not part of C++, but may be provided as an extension. While in this instance, for small len, the compiler has the option of allocating the space for the array on the stack, they are probably best avoided because of their non-standard nature; even in C, they are not required to be supported.
I am trying to find a more efficient method of loading variable length arrays of uint8_t bytes into a std::queue
The following code snippet is an attempt to reduce the actual code to something more usable as an example; so please forgive me if it's overly complex.
The code snippet works, with the exception of my inability to determine the actual length of each of the elements of the std::queue while they are still at the front of the queue. My question is, "Is there any way to push the pointer to the unsigned byte array into the queue without the intermediate step of creating a local array, copying the passed argument into it and then pushing the local pointer (See comments in code)?
#include <queue>
#include <string>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
using namespace std;
std::queue<uint8_t*> _q;
void routineSubroutine(uint8_t array_a[], int size_a)
{
/*
* Is there anyway to push the uint8 array_a into the queue (_q) without
* creating a new pointer to a byte array, copying the passed
* argument into it and the pushing it?
*/
uint8_t* a = new uint8_t[size_a];
memcpy((void*) a, (const void*) array_a, size_a);
_q.push(a);
}
int main(int argc, char** argv)
{
uint8_t myArray[512];
char cfa[] = {"I wish I was at Chick-Fil-A right now"};
memset((void*) myArray, 0x00, sizeof (myArray));
memcpy((void*) myArray, (const void*) cfa, strlen(cfa));
routineSubroutine(myArray, strlen(cfa));
char five[] = {"Five Guys will do in a pinch"};
memcpy((void*) myArray, (const void*) five, strlen(five));
routineSubroutine(myArray, strlen(five));
while (_q.size() > 0)
{
printf("Queue string value = %s\n", (char*) _q.front());
/*
* How do I go about determining the number of bytes in the uint8_t
* array, whose address is at the front of the queue?
*/
_q.pop();
}
return 0;
}
The code snippet works, with the exception of my inability to
determine the actual length of each of the elements of the std::queue
while they are still at the front of the queue
Use the proper container that knows its length/size and call the appropriate member function. A mere pointer doesn't do that.
Here is an example of your code rewritten to use std::vector:
#include <queue>
#include <string>
#include <vector>
#include <iostream>
std::queue<std::vector<uint8_t>> _q;
void routineSubroutine(const std::vector<uint8_t>& a)
{
_q.push(a);
}
int main(int argc, char** argv)
{
char cfa[] = {"I wish I was at Chick-Fil-A right now"};
routineSubroutine({std::begin(cfa), std::end(cfa)}); // creates a temp uint8_t vector
char five[] = {"Five Guys will do in a pinch"};
routineSubroutine({std::begin(five), std::end(five)}); // creates a temp uint8_t vector
while ( !_q.empty() )
{
// use the `write()` function to control the number of characters
std::cout.write(reinterpret_cast<const char *>(_q.front().data()), _q.front().size());
std::cout << "\n";
_q.pop();
}
return 0;
}
Output:
I wish I was at Chick-Fil-A right now
Five Guys will do in a pinch
Ultimately, I have full control over the type of queue I can use, while I have zero control over how the data is presented. Specifically the data is presented as a uint8_t* and size_t length. Thanks to #PaulMcKenie's example code I was able to come up with the following solution (which by the way is wicked fast):
std::queue<std::vector<uint8_t>> myQueue;
while(true)
{
// Pointer (myBuffer) and length (myLength) magically appear here
myQueue.push({myBuffer, (uint8_t*) (myBuffer + myLength)});
}
Problem solved.
I have a struct with an array in it. The size of this array needs to be 3*input_variable. How can I define a number externally, which is multiplied by an input value, that I can use in a struct to declare the length of an array?
I have tried defining the variable h outside of main as
extern h
then assigning it's value in main from the input variable.
I have also tried to use (in summary)
nt main(int argc, char** argv)
{
int input_variable;
std::cin << input_variable;
int h = input_variable * 3;
void some_function(); // function does some stuff
// with the structs
#ifndef ARRAY_SIZING
#define ARRAY_SIZING h
#endif
return 0;
}
struct _struct_
{
constexpr std::size_t b = ARRAY_SIZING;
double* arr[b];
};
int some_function()
{
// structs are used down here.
return 0;
}
I would love to be able to allocate the size of an array in a struct using an input parameter. Thank you.
Hm. Plain C-arrays in C++. Mostly never needed. OK, you want to interface to a library function.
My guess is that the library does not expect an array, but a pointer. And since your struct contains an array to pointer to doubles, I assume the lib wants to see a double**.
I hardly can imagine that old libraries use references or pointer to arrays, something like:
void function (double* (&array)[10]); // Reference to array
void function (double* (*array)[10]); // Pointer to array
because also here you need an array with a size known at compile time.
I'd rather expect something like
void function (double** array, size_t size); // Pointer to Pointer to double
So, use a std::vector like this:
std::vector<double *> arr(input_variable * 3);
And if you want to hand over the arrays data to the lib functions, then use the vectors data function.
function (arr.data());
You could also create the array with new.
Last hint: Do not use raw pointers.
I hope that I could help a little . . .
Why compiler doesn't pass size of array char *arr[] in parameters? I wanted to get get size of array passed by parameter but I guess it doesn't work because even char *a[] is char ** my question is why is it and can I make it work?
#include <stdio.h>
#include <stddef.h>
#include <stdio.h>
template<class T, size_t len>
constexpr size_t lengthof(T(&)[len])
{
return len;
}
void printarr(const char *a[]);
int main()
{
const char *a[] = { "aba", "bd", "cd" };
printarr(a);
}
void printarr(const char *a[])
{
for(size_t i = 0, c = lengthof(a); i < c; i++) {
printf("str = %s\n", a[i]);
}
}
You can make it work by using the same trick you used in your lengthof function template.
template<size_t len>
void printarr(const char* (&a)[len])
{
for(size_t i = 0, c = lengthof(a); i < c; i++) {
printf("str = %s\n", a[i]);
}
}
That has been a feature of C since the beginning and carried through into C++.
In the case of string arrays, the solution has been to add a trailing null character to mark the end.
The was probably done for the sake of efficiency when C started on ancient PDP computers.
Use strlen; or better yet std::string or std::vector.
Because this is required by the C++ standard, which inherited this behavior from C (and since C++ wants to stay compatible with C).
As function parameters, arrays are decayed into pointers.
You really want to use something like std::vector<std::string> instead. Learn more about standard C++ STL containers.
C++ is a language what provides low level access to system resources.
Processor is not working with objects, but with memory addresses.
If you want predefined structures, use Java, C#, python, or c++ libs like stl.
From the point of view of the language, your array doesn't have a length; the compiler cannot read your mind and decide where the array begins and where it ends, and it cannot waste memory and processing to perform range checking.
The closest thing to an array length is the number of consecutive memory spaces that have been allocated by a single new[] invocation, but such information is only authoritative for the purpose of allocating and deallocating memory: the "array" you want to process in your function might be only a portion of a single allocation (for example, you might allocate memory to load a whole text file and process each line separately).
I am writng a c++ program. I am parsing a file and initializing a structure. I have an array to initialize but I have to read the size of the array from the file. I want the array length read and array initialization in one function. If I pass the array pointer to another function and do a new, when the function returns, the pointer is destroyed, and I cannot see the initialized values. Is this expected or am I missing something. How can I overcome this problem?
You overcome this by forgetting everything about manual arrays, raw pointer passing* and new. This is C++, not 1991. So, a typical solution could be this:
#include <vector>
#include <cstdint>
#include <istream>
std::vector<uint32_t> read_data(std::istream & is)
{
uint32_t len;
is.read(reinterpret_cast<char*>(&len), sizeof(uint32_t));
std::vector<uint32_t> result(len);
for (uint32_t i = 0; i != len; ++i)
{
is.read(reinterpret_cast<char*>(&result[i]), sizeof(uint32_t));
}
return result;
}
(In high-quality code, the read commands would be surrounded by a conditional and errors would be handled, possibly by throwing an exception.)
Later:
#include "int_reader.hpp"
#include <fstream>
#include <iostream>
int main()
{
std::ifstream infile("thedata.bin", std::ios::binary);
std::vector<uint32_t> data = read_data(infile);
std::cout << "We read " << data.size() << " integers.\n";
}
*) The only raw pointer that has a place in general-purpose C++ is a char* when used for I/O operations, as demonstrated by this code. C++ defined char to be the machine's fundamental data unit type, and I/O happens in units of char.
There is no array pointer before you call new. So there's no way you could pass it to a function.
Likely what you're doing is passing the uninitialized, garbage value of the array pointer to a function. The function overwrites its copy of that garbage value with the correct pointer returned from new, but then the original function never sees that pointer.
You need to pass the function a pointer to the pointer. Then when it calls new, it can use the pointer to the pointer to update the caller's pointer. Like this:
void SomeFunction(void **SomePointer)
{
(*SomePointer) = malloc(1024);
}
void *MyPointer;
SomeFunction(&MyPointer);
You have to pass a pointer to a pointer in order to have a function allocate it for you
void allocateArrayOfT(T** objArray, size_t len) {
*objArray = new T[len];
}
You can call:
T* arrayPtr;
allocateArrayOfT(&arrayPtr, len);