-1

I have written following code where I am passing a WCHAR** reference to a function in order to get it filed inside the function. Inside the function, I am filling this 2 dimensional array. I am trying to use pass by reference to get this done.

BOOL get_file_names(WCHAR** outname)
{

    WCHAR **outhandlername = NULL;


    if (get_all_the_file_handelers( &outhandlername) > 0)
    {

        (*outname)[0] = *outhandlername[0];

    }

    return ret;
}

int get_all_the_file_handelers(WCHAR** outhandleName )
{



    for (i = 0; i < 10; i++)
    {
     WCHAR *handleName = get_handle_name(handle, i);

    outhandleName = (WCHAR**)realloc(outhandleName, sizeof(WCHAR)*(10 + 1));
    (*outhandleName) = (WCHAR*)realloc(*outhandleName, sizeof(WCHAR)*(1024));
    *outhandleName = handleName;

    }
    return 0;

}

But this does not seems to work, could anybody help me to understand how pass by reference works for array of WCHAR in a case like this. When I have WHCAR**, what is it correct to pass &WCHAR to second function, and inside the second function how should I be assigning the values for 2 dimensional WCHAR array


int _tmain(int argc, _TCHAR* argv[])
{
      WCHAR *outhandlename=NULL;
      get_file_names(&outhandlename);
      DBGLOG("handler name  %ls", outhandlename);

      return 0;
}

BOOL process_search_file_handle( WCHAR** str)
{
      *str = (WCHAR*) malloc(1024);
      *str = L"TestName";   
      return true;
}

BOOL get_file_names(WCHAR** outname)
    {

        WCHAR **outhandlername = NULL;


        if (get_all_the_file_handelers( &outhandlername) > 0)
        {

            *outname = outhandlername[0];
            DBGLOG("outhandlername value  %ls", outhandlername[0]);
            DBGLOG("str value  %ls", *outname);

        }

        return true;
    }
KItis
  • 5,476
  • 19
  • 64
  • 112
  • 1) There is no 2D array. 2) Any reason you don't use C++ features? – too honest for this site Mar 21 '17 at 02:19
  • Actually no reason, I am new to c++ and this happens to be my first project, I though this is possible, Thats the reason I chose this. What other approach I could take here – KItis Mar 21 '17 at 02:20
  • You are not passing by reference, you are passing by value... the `&` operator is the address-of operator. If you remove it in the function call to `get_all_the_file_handelers`, the code may do what you expect, however, I'm not sure how the memory allocated inside the function would know how to free itself. – MuertoExcobito Mar 21 '17 at 02:21
  • ` outhandleName = (WCHAR**)realloc(outhandleName, sizeof(WCHAR)*(10 + 1));` allocates 22 bytes but then casts being a pointer type. Pointers aren't the same size as `WCHAR`s. Maybe you meant `sizeof(WCHAR*)`. Next, `(*outhandleName) = (WCHAR*)realloc(*outhandleName, sizeof(WCHAR)*(1024));` tries to re-allocate what `*outhandleName` points to... but there was never a first allocation for that, so that's weird. But even if that succeeds, then `*outhandleName = handleName;` is just going to overwrite the pointer with the value from `handleName` thus leaking the previous allocation. – TheUndeadFish Mar 21 '17 at 02:26
  • When one gets into pointers to pointers... stuff just gets annoying. If you're new to C++, then it's overly complicated to be working at that level. Try using containers that can be easily resized and take care of the gritty details themselves, such as `std::vector` – TheUndeadFish Mar 21 '17 at 02:27
  • C doesn't have pass-by-reference. – user253751 Mar 21 '17 at 02:52
  • My suggestion is that you learn how to create and pass a `vector&` first. Muck around with pointers to pointers and their manual memory management in due time. – Davislor Mar 21 '17 at 03:14
  • If you really want to use only C types for this, though, you might find it simpler to define a rectangular instead of a ragged array: that is, an array of type `wchar_t[ROWS][COLUMNS]`. Make sure you use `strncmp( strings[i], strings[j], COLUMNS )`, `strncpy( dest, src, COLUMNS )`, etc: you always, *always*, **always** bounds-check your array operations in C. – Davislor Mar 21 '17 at 03:18

2 Answers2

2

Once you set outHandleName to the output of realloc, you've already overwritten outHandleName, so you won't be able to change the value of outHandleName from the calling function.

You could say:

*outHandleName = (WCHAR**) realloc(...);

You also will have to change the method header for get_all_the_file_handelers to:

int get_all_the_file_handelers(WCHAR *** outHandleName)

This is because you're using a pointer to a double pointer in this method.

Also, you're not passing by reference - you're passing by pointer.

Additionally, you shouldn't be using realloc here, since you're doing an initial allocation for the array. Your array of 10 elements should be allocated before your loop, like so:

*outHandleName = (WCHAR **)malloc(sizeof(WCHAR *)*(10+1));
(*outHandleName)[10] = NULL;

Note that null assignment - you're allocating space for 11 items in an array of 10 items, so I assume you're using the last item as a placeholder - as NULL - to mark the end of the array.

Finally, you don't need to allocate space for a string buffer for each of the 10 handles, since you're getting a string back from get_handle_name.

As a bonus, you aren't returning anything, even though the rest of your code suggests you are.

The final method would be:

int get_all_the_file_handelers(WCHAR ***outHandleName) {
  *outHandleName = (WCHAR **)malloc(sizeof(WCHAR *)*11);
  (*outHandleName)[10] = NULL;
  for(int i = 0; i < 10; i++) {
    WCHAR *handleName = get_handle_name(handle, i);
    (*outHandleName)[i] = handleName;
  }
  return .... /* WHAT AM I RETURNING?? */ ;
}
Anish Goyal
  • 2,799
  • 12
  • 17
  • Your solution worked for me, but I have one question, When I pass `wchar* variablename` into a function that takes `wchar &variablename`, then I tried to set this variable inside the function in the same manner like *variablename = L"Test Name";, but this value is not set when I try to print it after calling the function. to get it done, I had to use wcscpy_s, could u explain me a bit this difference – KItis Mar 21 '17 at 04:35
  • 1
    When you use wcscpy_s, you are copying a string from one location to another. You can't copy a string by using an assignment operator. If you take a variable `wchar *a` and say `*a = L"Test Name"`, you are essentially trying to stuff the address to your string into the memory region that a points to. What you really want to do is either replace the value of a with a pointer to your string literal, or you want to preallocate a buffer (`a = (wchar *)malloc(sizeof(wchar) * size_of_buffer)`), and then copy your string using wcscpy_s. – Anish Goyal Mar 21 '17 at 04:49
  • 1
    It's hard to explain, but basically it's impossible to copy a string with a single assignment. You could use a loop, but it's better to use a method that's already been written for copying a string. On the other hand, if you just want to set the value of a `wchar *` variable to a `wchar *` string literal, use an assignment without the preceding asterisk. You aren't trying to modify the region of memory that the "variablename" points to, you're trying to change what "variablename" points to; you're trying to make "variablename" point to your string, "Test Name". – Anish Goyal Mar 21 '17 at 04:52
  • Actually, could you provide the method you're talking about? – Anish Goyal Mar 21 '17 at 04:56
  • I updated the question by adding sample code which explains the question I asked, you may find the code below -------------- line – KItis Mar 21 '17 at 05:32
  • 1
    Hmm.... it might be because you're trying to print a WCHAR string with "%s" - try "%ls". – Anish Goyal Mar 21 '17 at 05:49
  • I have another question to ask ,this is inline with this same question. In the question I raised in the comment above, if I assign `*str=L"Test String"; `then it worked, but if I try to assign `*str = outhandlername[0];` then it again print `?????????????????` value, here the `outhandlername` is the input parameter That I am passing to `get_all_the_file_handelers` method. This case , I have to use wcscpy_s to get it working. – KItis Mar 21 '17 at 06:15
  • 1
    Are you passing `outhandlername` to this function as `&outhandlername`, or `outhandlername`? If the former, change your assignment to `*str = (*outhandlername)[0]`. – Anish Goyal Mar 21 '17 at 06:17
  • I updated the question, I am passing `outhandlername` as `&outhandlername` to the function `get_all_the_file_handelers`. `outhandlername` is of type `WCHAR **`, when I do the change you have mentioned, it says value of type `WCHAR` can not be assigned to entity of type `WCHAR*`, then I changed the expression to `**str = (*outhandlername)[0];` then it get run time error. – KItis Mar 21 '17 at 06:27
  • Based on your updated function, `*str = outhandlername[0]` would be correct. I'm not sure why it's printing `?????` though, unless you've reverted `%ls` to `%s` (which is what's currently in the code you posted). – Anish Goyal Mar 21 '17 at 06:30
  • what it prints is `?j?i????????????????????????????????????`, when I use `*str = outhandlername[0]`. I am using `%ls` as you pointed out. Are there any modifiers that I could try here. does it also mean that value is coming and it is just not printed properly – KItis Mar 21 '17 at 06:35
  • 1
    At that point, I'm not sure what else to suggest. Double check that your function get_handle_name is returning the correct values. Try printing the values from that function call out directly, and compare to your result later in the code. This will help you determine if the code you posted here is the issue, or if the issue is from other parts of your code. – Anish Goyal Mar 21 '17 at 06:38
  • I added two logs inside `get_file_names`, first log prints `?D?CC:\Users\tcadmin\Desktop\test.txt` this is the value expected and, second log print ` ?D` any thought on this – KItis Mar 21 '17 at 06:48
  • Actually, I found the reason, It was because, I had not initialized the outhandlename, after initializing it, `*str = (WCHAR*) malloc(1024);`, it is working. Thank you for the discussion, it helped me a lot to understand some c++ , but still a long way to go :) – KItis Mar 21 '17 at 07:07
  • Hmm.. That's odd - you shouldn't have to do that. When you allocate space like that, then follow it up with an assignment, the space you allocated is not used and goes to waste. I think you may have fixed your issue before adding that initialization. But also, I'm confused as to why you're printing str in get_file_names - you aren't modifying str in that method. Either way, I'm glad you have an implementation that works. – Anish Goyal Mar 21 '17 at 07:14
2

Here is some example code that generates a list of wide strings using the standard library. You should learn how to deal with arrays of pointers later, but I suggest you learn how to use the STL first.

#include <cstdlib>
#include <experimental/filesystem>
#include <iostream>
#include <locale>
#include <string>
#include <vector>

#if _WIN32 || _WIN64
// Windows needs a little non-standard magic for this to work.
#include <io.h>
#include <fcntl.h>
#include <locale.h>
#endif

using std::endl;
using std::size_t;
using std::wcout;
using std::experimental::filesystem::path;

void init_locale(void)
// Does magic so that wcout can work.
{
#if _WIN32 || _WIN64
  // Windows needs a little non-standard magic.
  constexpr char cp_utf16le[] = ".1200";
  setlocale( LC_ALL, cp_utf16le );
  _setmode( _fileno(stdout), _O_U16TEXT );
#else
  // The correct locale name may vary by OS, e.g., "en_US.utf8".
  constexpr char locale_name[] = "";
  std::locale::global(std::locale(locale_name));
  std::wcout.imbue(std::locale());
#endif
}

std::vector<std::wstring> files_in_wd()
// Returns a list of filenames in the current working directory.
{
  const path cwd = std::experimental::filesystem::current_path();
  std::vector<std::wstring> filenames;

  for ( const path& file : cwd )
    filenames.emplace_back( file.filename().wstring() );

  return filenames;
}

int main(void)
{
  init_locale();

  const std::vector<std::wstring> filenames = files_in_wd();

  for ( const std::wstring& ws : filenames )
    wcout << ws << endl;

  return EXIT_SUCCESS;
}
Davislor
  • 14,674
  • 2
  • 34
  • 49