I've got an array of arrays of TCHAR, where I store file extension.
TCHAR *extens[] = { L".*", L".txt", L".bat" };
In order to go through it, I'm calculating it's length.
int extCount = sizeof(extens) / sizeof(TCHAR);
But for some reason the extCount's value is 2. I think the problem is because this is wrong calculation method, but then, how to count the number of elements ("words") in this array correctly?
UPD: I'am passing this array to function:
void func(TCHAR *path, TCHAR **names, TCHAR **extensions);
When i'am calculating this array lenght outside function it show correct number, but inside it always workis wrong (returns 2 or 1).
UPD2:
I tried to redeclare array like this:
TCHAR *extens[] = { L".txt", L".bat", L".txt", NULL };
And now inside function i'am doing something like that:
TCHAR **p = extensions;
int extCount = 0;
while (*p != NULL)
{
extCount++;
*p++;
}
extCount = cnt;
wsprintf(temp, L"%d", cnt);
MessageBox(NULL, temp, temp, MB_OK);
It works, but looks like its not so effective, because of walking two arrays, isn't it?
TCHAR *extens[] is an array of pointers of type TCHAR. And the size of such an array will be array_length * sizeof(pointer)).
Note: sizeof(pointer) on a system will be same for all datatypes.
You have an array of TCHAR*.
To get the length of the following array:
TCHAR *extens[] = { L".*", L".txt", L".bat" };
You need to use:
sizeof(extens) / sizeof(TCHAR*)
First of all, you have an array of pointers so you need
extCount = sizeof(extens) / sizeof(TCHAR*);
to calculate its size. However, this assumes that extens is still of an array-type. Once you pass it to a function expecting a TCHAR**, the array will decay to a pointer and its size information will be lost.
I think your best option would be to rewrite this in terms of std::string and std::vector. This is C++ so you might as well use its facilities. If this is not possible for any reason, and the arrays are known at compile time, you could templatize the function on array-sizes:
template <size_t N, size_t M>
void func(TCHAR *path, TCHAR *(&names)[N], TCHAR *(&extensions)[M]);
The syntax is a bit messy maybe. For example, TCHAR *(&names)[N] is read as: "names is a reference to an array of N pointers to TCHAR". Here, the size N is deduced by the compiler as long as you don't let the array decay to a plain pointer.
Related
I'm trying to write a function, with a variable number of integer/int array parameters, that concatenates all the elements into a single 1-dimensional array. I'm struggling with one of the two scenarios where current_item turns out to be an array instead of just an integer. How can I access the individual elements of this array and assign them to pOutList?
typedef unsigned short WORD;
int PinListJoin(WORD * pOutList, ...) {
int index=0;
boolean isArray = false;
va_list next_item;
va_start(next_item, pOutList);
WORD current_item = va_arg(next_item, WORD);
int current_item_size = sizeof(current_item) / sizeof(WORD);
if (current_item_size > 1) {
isArray = true;
for (int pinidx = 0; pinidx < current_item_size; pinidx++) {
pOutList[index] = current_item;
index++;
}
}
else {
isArray = false;
pOutList[index] = current_item;
index++;
}
va_end(next_item);
return(current_item_size);
}
boolean isArray = false;
There is no boolean datatype in C++.
Also, the value of neither isArray nor index variable is ever used in the function.
typedef unsigned short WORD;
WORD current_item = va_arg(next_item, WORD);
This isn't going to work. Variadic arguments are promoted. unsigned short promotes to int (typically; on some exotic system, it might be unsigned int). Using the non-promoted type with va_arg will cause undefined behaviour. You could use a trick like this to get the correct type for any system:
using promoted_word = decltype(+WORD(0));
WORD current_item = WORD(va_arg(next_item, promoted_word));
WORD current_item = va_arg(next_item, WORD);
int current_item_size = sizeof(current_item) / sizeof(WORD);
The size of WORD divided by the size of WORD is always 1. There's no point in doing this.
I'm struggling with one of the two scenarios where current_item turns out to be an array instead of just an integer. How can I access the individual elements of this array and assign them to pOutList?
Function argument cannot be an array. But it can be a pointer to an element of an array, which I assume is what you mean. If that is the case, then you can get the pointer out of varargs like this:
WORD* current_item = va_arg(next_item, WORD*);
You can then copy the elements from array to array just like you would using any pointer to an element.
There's still two problems though: 1. There is no way of finding out the size of the array based on that pointer and 2. There is no way of finding out what type of arguments were passed (i.e. whether it was a( pointer to a)n array or an integer). You can take a look at the interface of printf for an idea of how that problem may be solved. It is solved there using a format string where those types are specified. The length of the array is solved by using a sentinel value (the null terminator character). Another approach is to pass the length as a separate argument.
More generally though: I recommend that you not use C style varargs at all in C++. It's just too easy to shoot yourself in the foot. Variadic templates are much safer and more powerful way to achieve similar things.
That said, I don't quite understand what you're attempting to do, so I cannot confirm whether it makes sense to use any form of variadics.
Suppose I have 20 string of different length, each of them is supposed to obtained similar to the following:
TCHAR *itemText[...];
SendMessage(hwndCombobox, CB_GETLBTEXT, i, (LPARAM)itemText);
Since I have an index for the items, I would like to use the above code in a for loop.
But because each item has different length, I can't use something like:
int itemLength = SendMessage(hwndCombobox, CB_GETLBTEXTLEN, i, 0);
TCHAR *itemText[itemLength];
Since using the message CB_GETLBTEXTLEN require the length at first, it is necessary to get the length. I know I can just use, for example, TCHAR *itemText[1024];, but I don't like this way personally.
I also tried to use new and delete, and other people suggest me to use vector along with std::string instead, as in this post delete pointers created by new in CallBack Function, but that leads to another problem in that the LPARAM parameter needed for CB_GETLBTEXT requires A pointer to the buffer that receives the string., so the following code doesn't work, since the last parameter is std::string, rather than a pointer which receives strings:
int i;
Vec<std::string> itemText;
for (i = 0; i < itemCount; i++) {
......... // Don't know how to initialize a string with a specified length.
SendMessage(win->hwndFindBox, CB_GETLBTEXT, i, (LPARAM)itemText.At(i));
}
I don't neither know how to initialize a std::string str with a specified length.
In fact, I would like to compare the typed string in the edit control of a combobox control with the items on this combobox. Do you have any suggestion to solve this problem or to do what I want to do?
You might have misunderstood suggestions to use std::vector with std::string. You should use std::vector<TCHAR> as a temporary buffer when reading the ComboBox item text (because you cannot write directly to the internal buffer used by std::basic_string), and then you can copy that into a std::basic_string<TCHAR> afterward if desired:
std::basic_string<TCHAR> s;
int itemLength = SendMessage(hwndCombobox, CB_GETLBTEXTLEN, i, 0);
if (itemLength != CB_ERR)
{
std::vector<TCHAR> buf(itemLength + 1 /* for NUL */);
SendMessage(hwndCombobox, CB_GETLBTEXT, i, reinterpret_cast<LPARAM>(&buf[0]));
s = &buf[0];
}
This works because std::vector is guaranteed to use contiguous memory, so &buf[0] should be equivalent to an array (assuming that buf is not empty, but in this case, we guarantee that it has at least 1 element).
I am doing some static analysis work on some old C++ code and my C++ is not the strongest. I have this piece of code:
void NIDP_clDPLogger::log(TCHAR *logString)
{
TCHAR temp_logString[1024] = {0};
_tcsncpy(temp_logString,logString,1024);
temp_logString[1023] = NULL;
...
The static analysis tool is complaining here of indexing logString (the parameter passed in to function) at 1024 when it may be shorter (the size varies, 1024 is the max. size I guess). So I guess my fix is to check the size of logString and use that, like this:
void NIDP_clDPLogger::log(TCHAR *logString)
{
size_t tempSize = sizeof(logString);
TCHAR temp_logString[tempSize] = {0};
_tcsncpy(temp_logString,logString,tempSize);
temp_logString[tempSize-1] = NULL;
I am just wondering, will this work OK? Can anybody see any flaws/problems? Building and testing this project is slightly difficult so I am basically just looking for a sanity check before I go through all that. Or is there a better way for me to do it? Can I pass a size_t value in to _tcsncpy, because a hardcoded int was there before?
Thanks for all help.
sizeof(logString) will return the size of a TCHAR*, not the size of the array passed as arrays decay to pointers when passed as argument.
If it is guaranteed that logString is null terminated you could obtain its length using _tcslen(). Otherwise, the only way to know the size of logString is to pass it into the function as another argument.
I am trying to learn a little c++ and I have a silly question. Consider this code:
TCHAR tempPath[255];
GetTempPath(255, tempPath);
Why does windows need the size of the var tempPath? I see that the GetTempPath is declared something like:
GetTempPath(dword size, buf LPTSTR);
How can windows change the buf value without the & operator? Should not the function be like that?
GetTempPath(buf &LPTSTR);
Can somebody provide a simple GetTempPath implementation sample so I can see how size is used?
EDIT:
Thanks for all your answers, they are all correct and I gave you all +1. But what I meant by "Can somebody provide a simple GetTempPath implementation) is that i have tried to code a function similar to the one windows uses, as follow:
void MyGetTempPath(int size, char* buf)
{
buf = "C:\\test\\";
}
int main(int argc, char *argv[])
{
char* tempPath = new TCHAR[255];
GetTempPathA(255, tempPath);
MessageBoxA(0, tempPath, "test", MB_OK);
return EXIT_SUCCESS;
}
But it does not work. MessageBox displays a "##$' string. How should MyGetTempPath be coded to work properly?
Windows needs the size as a safety precaution. It could crash the application if it copies characters past the end of the buffer. When you supply the length, it can prevent that.
Array variables work like pointers. They point to the data in the array. So there is no need for the & operator.
Not sure what kind of example you are looking for. Like I said, it just needs to verify it doesn't write more characters than there's room for.
An array cannot be passed into functions by-value. Instead, it's converted to a pointer to the first element, and that's passed to the function. Having a (non-const) pointer to data allows modification:
void foo(int* i)
{
if (i) (don't dereference null)
*i = 5; // dereference pointer, modify int
}
Likewise, the function now has a pointer to a TCHAR it can write to. It takes the size, then, so it knows exactly how many TCHAR's exist after that initial one. Otherwise it wouldn't know how large the array is.
GetTempPath() outputs into your "tempPath" character array. If you don't tell it how much space there is allocated in the array (255), it has no way of knowing whether or not it will have enough room to write the path string into tempPath.
Character arrays in C/C++ are pretty much just pointers to locations in memory. They don't contain other information about themselves, like instances of C++ or Java classes might. The meat and potatoes of the Windows API was designed before C++ really had much inertia, I think, so you'll often have to use older C style techniques and built-in data types to work with it.
Following wrapper can be tried, if you want to avoid the size:
template<typename CHAR_TYPE, unsigned int SIZE>
void MyGetTempPath (CHAR_TYPE (&array)[SIZE]) // 'return' value can be your choice
{
GetTempPath(SIZE, array);
}
Now you can use like below:
TCHAR tempPath[255];
MyGetTempPath(tempPath); // No need to pass size, it will count automatically
In your other question, why we do NOT use following:
GetTempPath(buf &LPTSTR);
is because, & is used when you want to pass a data type by reference (not address). I am not aware what buf is typecasted to but it should be some pointer type.
Can somebody provide a simple
GetTempPath implementation sample so I
can see how size is used?
First way (based on MAX_PATH constant):
TCHAR szPath[MAX_PATH];
GetTempPath(MAX_PATH, szPath);
Second way (based on GetTempPath description):
DWORD size;
LPTSTR lpszPath;
size = GetTempPath(0, NULL);
lpszPath = new TCHAR[size];
GetTempPath(size, lpszPath);
/* some code here */
delete[] lpszPath;
How can windows change the buf value without the & operator?
& operator is not needed because array name is the pointer to first array element (or to all array). Try next code to demonstrate this:
TCHAR sz[1];
if ((void*)sz == (void*)&sz) _tprintf(TEXT("sz equals to &sz \n"));
if ((void*)sz == (void*)&(sz[0])) _tprintf(TEXT("sz equals to &(sz[0]) \n"));
As requested, a very simple implementation.
bool MyGetTempPath(size_t size, char* buf)
{
const char* path = "C:\\test\\";
size_t len = strlen(path);
if(buf == NULL)
return false;
if(size < len + 1)
return false;
strncpy(buf, path, size);
return true;
}
An example call to the new function:
char buffer[256];
bool success = MyGetTempPath(256, buffer);
from http://msdn.microsoft.com/en-us/library/aa364992(v=vs.85).aspx
DWORD WINAPI GetTempPath(
__in DWORD nBufferLength,
__out LPTSTR lpBuffer
);
so GetTempPath is defined something like
GetTempPath(DWORD nBufferLength, LPTSTR& lpBuffer);
What mean, that compiler passes the value lpBuffer by referenece.
In C++, arrays cannot be passed simply as parameters. Meaning if I create a function like so:
void doSomething(char charArray[])
{
// if I want the array size
int size = sizeof(charArray);
// NO GOOD, will always get 4 (as in 4 bytes in the pointer)
}
I have no way of knowing how big the array is, since I have only a pointer to the array.
Which way do I have, without changing the method signature, to get the size of the array and iterate over it's data?
EDIT: just an addition regarding the solution. If the char array, specifically, was initialized like so:
char charArray[] = "i am a string";
then the \0 is already appended to the end of the array. In this case the answer (marked as accepted) works out of the box, so to speak.
Use templates. This technically doesn't fit your criteria, because it changes the signature, but calling code does not need to be modified.
void doSomething(char charArray[], size_t size)
{
// do stuff here
}
template<size_t N>
inline void doSomething(char (&charArray)[N])
{
doSomething(charArray, N);
}
This technique is used by Microsoft's Secure CRT functions and by STLSoft's array_proxy class template.
Without changing the signature? Append a sentinel element. For char arrays specifically, it could be the null-terminating '\0' which is used for standard C strings.
void doSomething(char charArray[])
{
char* p = charArray;
for (; *p != '\0'; ++p)
{
// if '\0' happens to be valid data for your app,
// then you can (maybe) use some other value as
// sentinel
}
int arraySize = p - charArray;
// now we know the array size, so we can do some thing
}
Of course, then your array itself cannot contain the sentinel element as content.
For other kinds of (i.e., non-char) arrays, it could be any value which is not legal data. If no such value exists, then this method does not work.
Moreover, this requires co-operation on the caller side. You really have to make sure that the caller reserves an array of arraySize + 1 elements, and always sets the sentinel element.
However, if you really cannot change the signature, your options are rather limited.
In general when working with C or low-level C++, you might consider retraining your brain to never consider writing array parameters to a function, because the C compiler will always treat them as pointers anyway. In essence, by typing those square brackets you are fooling yourself in thinking that a real array is being passed, complete with size information. In reality, in C you can only pass pointers. The function
void foo(char a[])
{
// Do something...
}
is, from the point of view of the C compiler, exactly equivalent to:
void foo(char * a)
{
// Do something
}
and obviously that nekkid char pointer contains no length information.
If you're stuck in a corner and can't change the function signature, consider using a length prefix as suggested above. A non-portable but compatible hack is to specify the array length in an size_t field located before the array, something like this:
void foo(char * a)
{
int cplusplus_len = reinterpret_cast<std::size_t *>(a)[-1];
int c_len = ((size_t *)a)[-1];
}
Obviously your caller needs to create the arrays in the appropriate way before passing them to foo.
Needless to say this is a horrible hack, but this trick can get out of trouble in a pinch.
It actually used to be a quite common solution to pass the length in the first element of the array. This kind of structure is often called BSTR (for “BASIC string”), even though this also denoted different (but similar) types.
The advantage over the accepted solution is that determining the length using a sentinel is slow for large strings. The disadvantage is obviously that this is a rather low-level hack that respects neither types nor structure.
In the form given below it also only works for strings of length <= 255. However, this can easily be expanded by storing the length in more than one byte.
void doSomething(char* charArray)
{
// Cast unnecessary but I prefer explicit type conversions.
std::size_t length = static_cast<std::size_t>(static_cast<unsigned char>(charArray[0]));
// … do something.
}
if it's nullterminated, strlen() would work.
You can't determine the size from charArray alone. That information is not automatically passed to the function.
Of course if it's a null-terminated string you can use strlen(), but you have probably considered that already!
Consider passing a std::vector<char> & parameter, or a pair of pointers, or a pointer plus a size parameter.
This is actually more C than C++, in C++ you'd probably rather use a std::vector. However, in C there's no way to know the size of an array. The compile will allow you to do a sizeof if the array was declared in the current scope, and only if it was explicitly declared with a size (EDIT: and "with a size", I mean that it was either declared with an integer size or initialized at declaration, as opposed to being passed as a parameter, thanks for the downvote).
The common solution in C is to pass a second parameter describing the number of elements in the array.
EDIT:
Sorry, missed the part about not wanting to change the method signature. Then there's no solution except as described by others as well, if there's some data that is not allowed within the array, it can be used as a terminator (0 in C-strings, -1 is also fairly common, but it depends on your actual data-type, assuming the char array is hypothetical)
In order for a function to know the number of items in an array that has been passed to it, you must do one of two things:
Pass in a size parameter
Put the size information in the array somehow.
You can do the latter in a few ways:
Terminate it with a NULL or some
other sentinel that won't occur in
normal data.
store the item count in the first entry if the array holds numbers
store a pointer to the last entry if the array contains pointers
try using strlen(charArray);
using the cstring header file. this will produce the number of characters including spaces till it reaches the closing ".
You are guarranteed to receive 4 in a 32-bit PC and that's the correct answer. because of the reason explained here and here.
The short answer is, you are actually testing the sizeof a pointer rather than an array, because "the array is implicitly converted, or decays, into a pointer. The pointer, alas, doesn't store the array's dimension; it doesn't even tell you that the variable in question is an array."
Now that you are using C++, boost::array is a better choice than raw arrays. Because it's an object, you won't loose the dimention info now.
I think you can do this:
size_t size = sizeof(array)/sizeof(array[0]);
PS: I think that the title of this topic isn't correct, too.
Dude you can have a global variable to store the size of the array which will be accessible throughout the program. At least you can pass the size of the array from the main() function to the global variable and you will not even have to change the method signature as the size will be available globally.
Please see example:
#include<...>
using namespace std;
int size; //global variable
//your code
void doSomething(char charArray[])
{
//size available
}