0

I am making an fstream clone thats supposed to be more simple to use. I have multiple "write" functions for writing to the file, however, these versions added a new line at the end, so to try and find a way to eliminate that blank last line, i made a write_test function to find a way to write without adding a final blank line.

Pretty simple.

In theory, it should work. However, I cannot iterate through the string array because i cant get the size of it.

I tried sizeof(lines)/sizeof(std::string) as well as sizeof(lines)/sizeof(lines[0]) and both returned the same result, 0.

My goal is to get the actual size of the string array so the function can iterate through it.

Here is my main.cpp file,

#include "bstdlib/fstream-new.hpp"

int main(){

    // make object  
    bstd::fstream::file fs("./output/file.txt");

    // string array
    std::string str1, str2, str3;
    str1="hello";
    str2="world";
    str3="!!!!!";

    std::string strs[]={str1, str2, str3};
    // write it, this is where the cactus on my seat lies
    fs.write_test(strs);
}

Here is the write_test function

            void write_test (std::string lines...) {
                // make fstream object
                std::fstream fs(this->fp.c_str(), std::fstream::out);
                // get size of array
                int range = sizeof(lines) / sizeof(lines[0]);
                std::cout << range; // print
                // make 1 grand string of each line 
                std::string grand_string;
                for (int i=0; i<range-2; i++) {
                    grand_string += (lines[i]+"\n");
                }
                grand_string += lines[range-1];
                // write, i used .c_str() because i felt as though that was what type it takes
                fs << grand_string.c_str();
                fs.close();
                this->scan(); // just a function to read the file and update this->lines, irrelevant to the problem
            }

It prints the size of the string array, 0. Of course, it writes nothing to the file, leaving it blank.

  • 3
    That code shouldn't compile as is. You can't just declare variadic function and expect its first parameter to behave like an array. – Etienne de Martel Sep 15 '22 at 03:07
  • 1
    You need to go back to your C++ book and review stuff. If you need a new [C++ book you can try looking here](https://stackoverflow.com/q/388242/631266). sizeof isn't usable for what you are trying to do. If you insist on trying to pass a raw array, you must also pass its length. Consider passing a std::vector by reference instead. – Avi Berger Sep 15 '22 at 03:09
  • @EtiennedeMartel `std::string` supports `operator[]` so it is plausible that the code might compile, although not behave as intended of course . – M.M Sep 15 '22 at 03:57
  • @M.M How are is `fs.write_test(strs)` supposed to compile? You can't pass an `std::string` array to a function expecting an `std::string`. – Etienne de Martel Sep 15 '22 at 13:43
  • i thought the use of elipses (...) was similar to pythons *args? its not a singular string – Formik Dev Sep 15 '22 at 23:12
  • @FormikDev Ah, no, it's not really like that. Those ellipses, even in C++, are actually a C feature known as [variadic functions](https://en.cppreference.com/w/c/variadic), and they come with their own set of limitations and quirks that make them ill suited for most applications in modern C++ code. What's important here is that adding `...` to a parameter does not make that parameter an array. If you want your function to take an array, give it an array. C++ doesn't have any syntactic sugar for that. – Etienne de Martel Sep 17 '22 at 03:21

1 Answers1

1

If you want to iterate over the entire strs array in the function write_test, then the function write_test must know the following:

  1. It needs to know where the array starts, for example it needs a pointer to the start of the array.

  2. It needs to know where the array ends, for example it needs an integer which specifies the number of elements in the array.

In your posted code, the function main is giving the function write_test a pointer to the start of the array, but it is not providing any information about the size or the end of the array. Therefore, it is not possible for the function write_test to iterate over the entire array.

The line

fs.write_test(strs);

in the function main will not pass the actual array strs to the function write_test. Rather, the expression strs will decay to &strs[0], i.e. it will decay to a pointer to the first element of the array. Therefore, no information about the size of the array is passed to the function write_test.

However, you can explicity pass the size of the array as a separate parameter:

fs.write_test( strs, sizeof strs / sizeof *strs );

For this to work, you would have to change the signature of the function write_test to the following:

void write_test( std::string lines[], size_t length )

A better alternative would be to use a std::vector instead, because that type of object will not decay to a pointer when passed to a function. Therefore, all information about the length of the std::vector will be retained and can be easily accessed by the called function.

In order to create the std::vector and pass it to the function write_test, you could use the following code:

#include <iostream>
#include <string>
#include <vector>

#include "bstdlib/fstream-new.hpp"

int main() {

    // make object  
    bstd::fstream::file fs("./output/file.txt");

    // string array
    std::string str1, str2, str3;
    str1="hello";
    str2="world";
    str3="!!!!!";

    std::vector<std::string> strs{ str1, str2, str3 };

    fs.write_test( strs );
}

For this to work, the signature of write_test would have to be changed to the following:

void write_test( std::vector<std::string> &lines )
Andreas Wenzel
  • 22,760
  • 4
  • 24
  • 39
  • thank you this was the most helpful out of all. But why size_t for sizeof(......)? why not int? – Formik Dev Sep 15 '22 at 23:16
  • also why pass a reference? I wouldnt be manipulating the vector – Formik Dev Sep 15 '22 at 23:16
  • @FormikDev: The `sizeof` operator will always evaluate to an integer of type `size_t`. A `size_t` is usually able to represent a wider range of positive values than `int`. However, as long as the number of elements in the array does not get so large that the number is not representable as an `int`, then it should not matter whether you use `size_t` or `int`. You may get a warning from your compiler if you use `int`, though. – Andreas Wenzel Sep 15 '22 at 23:43
  • @FormikDev: If you don't pass the array as a reference, the entire array will be copied when it is passed to the function. This can be bad for performance. Since the array is rather small, it probably won't matter in this case, but it is generally better to pass arrays by reference, if you don't want the called function to receive its own copy of the array. If the called function will not modify the array, you can also pass the array by `const` reference. This may allow additional optimizations by the compiler. – Andreas Wenzel Sep 15 '22 at 23:46