Placing floats from string into void array - c++

I get a segmentation fault when my function reads floats from a string and places them in a void array. The segfault occurs after about 200 iterations of the for loop in the following code:
// Allocate memory
void** data;
data = (void**)malloc(num_vals * sizeof(float));
// Convert text to floats
(*(float**)data)[0] = atof(strtok(text, " "));
for(int index=1; index<num_vals; index++) {
(*(float**)data)[index] = atof(strtok(NULL, " "));
std::cout << (*(float**)data)[index] << std::endl;
}
The void array is necessary because the size and type of data in the string are determined at run-time. I've tried increasing the malloc size, but it doesn't change anything. Any thoughts?

Seriously??
std::vector<float> data;
std::istringstream str(text);
float fv;
while (str >> fv)
{
data.push_back(fv);
}
Now that's c++

As much as it pains me to do so, here is a version of your code that probably does what you want.
// Allocate memory
void* data;
data = malloc(num_vals * sizeof(float));
// Convert text to floats
((float*)data)[0] = atof(strtok(text, " "));
for(int index=1; index<num_vals; index++) {
((float*)data)[index] = atof(strtok(NULL, " "));
std::cout << ((float*)data)[index] << '\n';
}
Note, however, that if you worked for me and tried to check in that code, we would have a serious discussion about your choice of career.
I'd rather see something like this:
std::vector<float> v;
std::copy(std::istream_iterator<float>(std::istringstream(text)),
std::istream_iterator<float>(),
std::back_inserter(v));
P.s. Rob's rule #47: Never say std::endl when you mean '\n'.

Why do you convert to void ** ??? You code contains couple errors on indexing, so let me show some reasonable changes
float* data;
data = (float*)malloc(num_vals * sizeof(float));
// Convert text to floats
data[0] = atof(strtok(text, " "));
for(int index=1; index<num_vals; index++) {
data[index] = atof(strtok(NULL, " "));
std::cout << data[index] << std::endl;
}

You got your types mixed up in your inexplicable attempt to create this monster under the pretence of writing "C++". Anyway. what you're mallocing is nothing but a float*, so you need to cast data back to float*:
((float*)data)[0] = myfloat;

I think, since you are defining a pointer of void pointer and allocating/casting it to pointer of void pointer, it allocates 4 byte memory for each element because in C/C++, regardles of the type of the pointer, pointers are always 4 bytes which are not big enough floats.

There're several issues. One is - data should be void *, you have redundant *. Other might be alignment, i'm not sure you are able to place a float in any location in the memory.

Related

How do handle varying array sizes as arguments for a function?

I managed to convert an over 5000 line code of Fortran 77 program to C++ manually but the conversion didn't go according to plan. So I am trying to debug the C++ program using my Fortran 77 program. In fortran I developed a subroutine that takes an array and prints out the array index and its value into a comma delimited file. I am trying to do the similar thing in C++. but run foul of the "double temp1[tempi]" declaration. The array does not have to be the same size in all the calls to the function. So I cant code it a say "double temp1[21]" because the next time it is 25. Fortran passes arrays by reference. What do you propose I do.
I managed to to this for the Fortran program. The idea is to take the variable memory dump from the c++ program and compare the values in Excel using vba to see which one changes the most and then to focus on that variable in the C++ program a starting debugging point.
c++ code logic:
void singlearrayd(double temp1[tempi], int tempi, string str1){
for (int md_i = 1; md_i <= tempi; md_i++){
cout << temp1[md_i] << "," << str1 << "(" << md_i << ")";
}
}
int main(){
double askin[22];
double fm[26];
singlearrayd(askin,22,"askin");
singlearrayd(fm,26,"fm");
return 0;
}
Fortran 77 code logic:
PROGRAM PRINT_MEMORY
real*8 :: ASKIN(21)
real*8 :: FM(25)
CALL SINGLEARRAYD(ASKIN,21,"ASKIN")
CALL SINGLEARRAYD(FM,25,"FM")
END PRINT_MEMORY
SUBROUTINE SINGLEARRAYD(TEMP1,TEMPI,STR1)
IMPLICIT NONE
CHARACTER(LEN=*) :: STR1
INTEGER*4 MD_I,TEMPI
REAL*8, DIMENSION(1:TEMPI) :: TEMP1
DO MD_I = 1, TEMPI
WRITE(51,'(ES25.16E3,A1,A25,A1,I5,A1)') TEMP1(MD_I),',',STR1,'(',
1 MD_I,')'
ENDDO
ENDSUBROUTINE SINGLEARRAYD
There are multiple problems in your code.
In C++, a native array (like your askin in main()) is converted into a pointer when passed to a function. So there is no need to declare a dimension on the array in the argument list BUT it is still necessary to pass a second argument, as you are specifying the size.
This means the C++ function should have the form
void singlearrayd(double temp1[], int tempi, std::string str1)
or (equivalently)
void singlearrayd(double *temp1, int tempi, std::string str1)
Note in the above that I have specified the type of the third argument by its full name as std::string. In a lot of cases, it is better avoid using namespace std.
The second problem is that you are assuming Fortran array indexing and C++ array indexing are the same. In reality, Fortran array indexing is 1-based (the first element of an array has index one, by default) and C++ array indexing is 0-based (the first element on an array has index zero). Using Fortran array indexing in C++ causes undefined behaviour, because it will access elements outside the valid range.
The third (potential) problem is that your function defines two variables named md_i (one in the function, and one within the loop). It is better to avoid doing that.
Addressing all of the above will turn your function to (in full)
void singlearrayd(double temp1[], int tempi, std::string str1)
{
for (int md_i = 0; md_i < tempi; ++md_i) // note the differences here carefully
{
cout << temp1[md_i] << "," << str1 << "(" << md_i << ")";
}
}
The fourth problem is that main() in C++ returns int, not void.
The fifth problem is that main() does not initialize the arrays before singlearrayd() prints them. In Fortran, arrays that are local to a function are (often) zero-initialised. In C++, they are uninitialised by default, so accessing their values (e.g. to print them) gives undefined behaviour.
int main()
{
double askin[21] = {0.0}; // initialise the first element. Other elements are initialised to zero
double fm[21] = {0.0};
singlearrayd(askin,21,"askin");
singlearrayd(fm,25,"fm");
}
That will get your code working. Practically, however, there are improvements possible. The first improvement is to use a standard container rather than an array. Standard containers know their size, so that allows simplifying your function. Second, pass non-trivial arguments (like containers or strings) by reference - and preferably const reference if no change is being made to the argument. Unlike Fortran, where function arguments are often passed by reference BY DEFAULT, it is necessary to DELIBERATELY introduce references in C++.
#include <vector>
void singlearrayd(const std::vector<double> &temp1, const std::string &str1)
{
for (std::size_t md_i = 0; md_i < temp1.size(); ++md_i)
{
cout << temp1[md_i] << "," << str1 << "(" << md_i << ")";
}
}
int main()
{
std::vector<double> askin(21); // askin has 21 elements, initialised to zero
std::vector<double> fm(21);
singlearrayd(askin, "askin");
singlearrayd(fm, "fm");
}
C++ containers also support iterators - which are safer in practice AND often more efficient - than using array indexing. I'll leave it as an exercise for you to learn how to use those.
A key message however: don't assume that a simple mechanical translation from Fortran to C++ will work. You have already demonstrated pitfalls of such an assumption. Take the time to learn C++ BEFORE trying to translate too much code from Fortran to C++. That is necessary both to get the C++ code working correctly and also to get it running efficiently.
A more modern implementation would be
#include <string>
#include <array>
#include <iostream>
template <std::size_t size, class U>
void singlearrayd(const std::array<U, size>& temp1, const std::string& str1){
int i = 0;
for (const auto& x : temp1)
std::cout << x << "," << str1 << "(" << (i++) << ")";
}
int main(){
std::array<double, 21> askin;
std::array<double, 21> fm;
singlearrayd(askin, "askin");
singlearrayd(fm, "fm");
return 0;
}
Please note that in the code above the two arrays askin and fm are not initialized. Presumably, in the real code you would have already initialized them before calling singlarrayd.
Also, remember that main must return an int.
Thank you for your valuable insight and comments. I think the best approach was use
void singlearrayd(double *temp1, int tempi, std::string str1)
Extending this idea and doing some more research using google I was able to extend this idea to handle 2D and 3D arrays.
void doublearrayd(double *temp1, int tempi, int tempj, std::string str1){
for (int md_j = 1; md_j<tempj; md_j++){
for (int md_i = 1; md_i<tempi; md_i++){
std::cout << *(temp1 + md_i*tempj + md_j) << "," << str1 << "(" << md_i << ";" << md_j << ")" << std::endl;
}
}
}
void triplearrayd(double *temp1, int tempi, int tempj, int tempk, std::string str1){
for (int md_k = 1; md_k < tempk; md_k++){
for (int md_j = 1; md_j<tempj; md_j++){
for (int md_i = 1; md_i<tempi; md_i++){
std::cout << *(temp1 + md_i*tempj*tempk + md_j*tempk + md_k) << "," << str1 << "(" << md_i << ";" << md_j << ";" << md_k << ")" << std::endl;
}
}
}
}
https://en.wikipedia.org/wiki/Row-_and_column-major_order
How can I pass a dynamic multidimensional array to a function?

Deleting dynamically sized array from function

In this part of my code (receiving the time) I have a dynamically sized array of chars. This is for a school project and dynamically sized arrays are required.
char* msgtime::getTime() {
std::string t;
t.append(std::to_string(hour));
t.append(":");
t.append(std::to_string(minute));
char *charTime = new char[t.length()];
strcpy(charTime, t.c_str());
return charTime;
}
However, I can't delete the charTime since I am returning the value. I tried following another question I saw on here to return it into a char* in the main program then delete that when I'm done with it. The code here is what the function is returning to:
void receive(packet &data, SOCKET con) {
msgtime tim;
cout << "Receiving data" << endl;
int in = recv(con, (char*)&data, sizeof(data), 0);
cout << "Data received: " << in << endl;
tim.updateTime();
char *newTime = tim.getTime();
strcpy(data.time, newTime);
delete[] newTime;
}
Except when I run it I get this error:
HEAP CORRUPTION DETECTED: after Normal block (#183) at 0x00129330
CRT detected that the application wrote to memory after the end of heap buffer.
I need to delete the charTime in the getTime function to plug the memory leak but I can't figure out how to do it. Any help is GREATLY appreciated!
You don't allocate enough space, one more char is required to store null terminator:
char *charTime = new char[t.length() + 1];

Concatenating an array size in cout statement

I'm trying to output the number of element-objects in my array, but the syntax for that is not the same as it is for Java:
// print list of all messages to the console
void viewSent()
{
cout << "You have " << sent.size() << " new messages.\n";//Error: left of '.size' must have class/struct,union
std::cout << "Index Subject" << '\n';
for (size_t i = 0; i < sent.size(); ++i)
{
std::cout << i << " : " << sent[i].getSubject() << '\n';
}
}
if the .size doesn't work in C++ syntax, what does?
The C++ equivalent of a Java array is std::vector. sent.size() is the correct way to get the size.
You didn't post your definition of sent but it should be std::vector<YourObject> sent;, perhaps with initial size and/or values also specified.
I'm guessing you tried to use a C-style array -- don't do that, C-style arrays have strange syntax and behaviour for historical reasons and there is really no need to use them ever in C++.
If your array is a C-Array, you can loop through it like this:
for (size_t i = 0; i < (sizeof(sent) / sizeof(TYPE)); ++i)
... where TYPE is the underlying type of the array.
For example, if sent is defined as:
int sent[];
... then TYPE would be int, like this:
for (size_t i = 0; i < (sizeof(sent) / sizeof(int)); ++i)
A C-Array is not an object. So it has no members or methods and you cannot use the member operator with it. The sizeof operator is used to find the size of a fundamental type, in bytes. sizeof returns an integer value of type size_t.

Confusion about sizeof operator

I am using C++ on Mac OSX Lion and I have created the following code:
float* floatArray = new float[10];
for(int i = 0; i < 10; i++)
{
floatArray[i] = 0.0 ;
}
std::cout<< "Test size of a float " << sizeof(floatArray[0]) << std::endl;
// The value is 4 byte which is what I would expect.
std::cout<< "Test the size of the whole array" << sizeof(floatArray) <<std::endl;
// the value is 8. I would have expected the value to be 40 bytes.
What am I not understanding?
Thanks in Advance
The expression sizeof(floatArray) returns the size of the pointer, not what it points to.
In your system, size of the pointer in memory is 8 bytes.
Sizeof() operator just looks at the size of that variable in memory. So it prints the size of the float pointer.
You can find more detail here.
How to find the 'sizeof' (a pointer pointing to an array)?
Compare it with this (which actually is an array):
float floatArray[10] = {0.0};
std::cout<< "sizeof a float " << sizeof(floatArray[0]) << std::endl;
std::cout<< "sizeof the whole array " << sizeof(floatArray) << std::endl;
and then, if you need to use dynamically-sized or allocated arrays, consider using std::vector instead.
Your second sizeof(floatArray) is actually returning the size of the pointer, not the size of the array.
See here
The sizeof operator has no knowledge what and how many elements a pointer points to (except when you feed it an array, but that's not a pointer, again). So it returns sizeof (float *) - and as you're probably on 64-bit, the size of a pointer is 8 bytes long.

Trying to initialize a list with values but not working when I use a variable to create the size

This is my second time using C++ and I'm trying to port some Java code I made but am having trouble understanding some behavior. I have a list of data and want to create another list of the same size but the values are default to zero(in Java I use Arrays.fill(list, 0); after creating it). When I try to do something similar in C++ I get variable-sized object 'list1' may not be initialized
Here's a code to better example:
#include <iostream>
#include <boost/assign/std/vector.hpp> // for 'operator+=()'
using namespace std;
using namespace boost::assign;
int main()
{
cout << "Hello World!" << endl;
vector<short> data;
data += -40, -30,-10, 20, 50;
//int coeff [data.size()];
cout << "data array size is " << data.size() << endl;
short list1 [data.size()] = {0}; //does not work
for (int i =0; i<data.size(); i++) {
cout << "data is " << list1[i] << endl;
}
cout << "********** try 2 **************" << endl;
//this works if I use a actual number to create the list but I want to declare it at runtime
short list2 [5] = {0};
for (int ii=0;ii<5;ii++) {
cout << "data is " << list2[ii] << endl;
}
return 0;
}
Like I mentioned, I'm completely green when I comes to C++ (I have read a book and done a few tutorials) so I may be doing something completely wrong. In the event I cannot do this at runtime and only at compile time, is there something else I can use to get the same result?
c++ does not have dynamically sized arrays, so this is illegal:
short list1 [data.size()];
but you can use a vector:
std::vector<short> list1(data.size(),0);
That creates a vector of the same length as data, full of zeroes.
If you want an array whose size is determined at runtime, you'll have to allocate it.
short * list1 = new short[data.size()];
//do stuff
delete [] list1; //we don't want to leak
You typically want to avoid naked pointers whenever possible, so the cleaner solution is what juanchopanza suggested and try to use std::vector.
The equivalent of Arrays.fill(list, 0); for a C++ vector looks like std::fill(list.begin(), list.end(), 0);
You can also simply declare a std::vector<short> list1(data.size()); to create it with zero initialized values or with a specific value std::vector<short> list1(data.size(), 0);