I am making a patcher for a game but I get the error "initializer-string for array of array of chars is too long" from Mingw. I am trying to make a multidimensional array of chars to contain what functions to patch.
I have checked for other questions about this and found one where the asker forgot to add commas to the end of every string literal, but I have done that already.
Could anyone help me?
The source that triggers the error:
char patches2[][64] = {
"CreateMutexW",
"CreateRemoteThread",
"CreateRemoteThreadEx",
"?strcmp#unicode_string_trait#esl##SAJPB_W0#Z",
"??0?$CStringT#_WVunicode_string_trait#esl##Vunicode_string_implement#2##esl##QAE#XZ",
"??0?$CStringT#_WVunicode_string_trait#esl##Vunicode_string_implement#2##esl##QAE#PB_W#Z",
"??4?$CStringT#_WVunicode_string_trait#esl##Vunicode_string_implement#2##esl##QAEAAV01#PB_W#Z",
"?GetContent#?$CStringT#_WVunicode_string_trait#esl##Vunicode_string_implement#2##esl##QBEPB_WXZ",
"?SetLookUpOrder#CFileSystem#esl##QAEXW4EFileLookUpOrder#esl_constant#2##Z",
"??1package_file_item#esl##QAE#XZ",
"??1CFormatter#esl##QAE#XZ",
"??6CFormatter#esl##QAEAAV01#K#Z",
"??6CFormatter#esl##QAEAAV01#G#Z",
"??6CFormatter#esl##QAEAAV01#M#Z",
"??6CFormatter#esl##QAEAAV01#PB_W#Z",
"??BCFormatter#esl##QBE?AV?$CStringT#_WVunicode_string_trait#esl##Vunicode_string_implement#2##1#XZ",
"?__time#etc#esl##YAKXZ",
"?ReadFSAA#CGameOptionMgr#pleione##QAE?AW4EFSAA#pleione_constant#2#XZ",
"?ReadFSAAQuality#CGameOptionMgr#pleione##QAEKXZ",
"?CleanUp#CPleione#pleione##QAE_NXZ",
"?SetSkyTime#CAtmosphere#pleione##QAEXM#Z",
"?SetCamera#CCameraControl#pleione##QAEXPAVCScene#2#PAVITerrain#2#KFF#Z",
"?GetObjectId#CObject#mint##QBE_KXZ",
"?ReadU8#CMessage#mint##QAEEXZ",
"?GetLuck#IParameter#core##QAEMXZ",
"?GetGateLocalName#CGateMgr#core##QBE?BV?$CStringT#_WVunicode_string_trait#esl##Vunicode_string_implement#2##esl##AB v34##Z",
"?GetLife#IParameterBase2#core##QAEMXZ",
"?GetLifeMax#IParameterBase2#core##QAEMXZ",
"?IsEiry#SItemEgoInfo##QBE_NXZ",
"?SetFog#CDungeonRegion#core##QAEX_N#Z",
"?GetTargetCombatPower#ICharacter#core##QAE?AW4ECombatPower##PBname2##Z",
"?GetCombatPower#IParameterBase2#core##QBEMXZ",
"?GetInterfaceDurability#IItem#core##QBEKXZ",
"?GetInterfaceDurabilityMax#IItem#core##QBEKXZ",
"?GetColor#IItem#core##QBEKK#Z",
"?IsElf#ICharacter#core##QBE_NXZ",
"?IsGiant#ICharacter#core##QBE_NXZ",
"?IsPet#ICharacter#core##QBE_NXZ",
"?IsNPC#ICharacter#core##QBE_NXZ",
"?IsNamedNPC#ICharacter#core##QBE_NXZ",
"?IsGoodNPC#ICharacter#core##QBE_NXZ",
"?Compile#CDefaultCompiler#pleione##UAEPAVCCompiledText#2#ABV?$CStringT#_WVunicode_string_trait#esl##Vunicode_string_implement#2##esl##ABUtext_option#2##Z",
"?Compile#CDefaultTagCompiler#pleione##UAEPAVCCompiledText#2#ABV?$CStringT#_WVunicode_string_trait#esl##Vunicode_string_implement#2##esl##ABUtext_option#2##Z",
"?Compile#CHTMLCompiler#pleione##UAEPAVCCompiledText#2#ABV?$CStringT#_WVunicode_string_trait#esl##Vunicode_string_implement#2##esl##ABUtext_option#2##Z",
"?_RenderGlowOverlay#CRendererContext#pleione##AAEXXZ",
"?GetExploLevel#IParameterBase2#core##QBEGXZ",
"?GetExploExpPercent#IParameter#core##QBEMXZ",
"?ParseCommand#CUserConsoleMgr#core##QBE_NABV?$CStringT#_WVunicode_string_trait#esl##Vunicode_string_implement#2##esl##AAVCUserConsole#2##Z",
"?Instance#CLocalizer#core##SAAAname2#XZ",
"?GetLocalText#CLocalizer#core##QBE?AVCFormatter#esl##ABV?$CStringT#_WVunicode_string_trait#esl##Vunicode_string_implement#2##4##Z",
"?stdapi_ShowChattingMessage#core##YAX_KABV?$CStringT#_WVunicode_string_trait#esl##Vunicode_string_implement#2##esl##1KKE#Z",
"?stdapi_ShowCaption#core##YAX_KABV?$CStringT#_WVunicode_string_trait#esl##Vunicode_string_implement#2##esl##W4EMessageCaptionType##KKK0#Z",
"?stdapi_GetGlobalTime#core##YA_KXZ",
"?stdapi_GlobalTimeToGameTime#core##YAX_KAAK11#Z",
"?IsUsingNaosSupport#IServiceMgr#core##QBE_NXZ",
"?CheckFastStringID#IProp#core##QBE_NPB_W#Z",
"?IsUsableContents#IServiceMgr#core##QBE_NW4EServiceContents#2##Z",
"?IsTransformed#ITransformMgr#core##QBE_NXZ",
"?GetFullSuitID#ICharacter#core##QAEKXZ",
"?IsBroken#IItem#core##QBE_NXZ",
"?CheckFastStringID#IItem#core##QBE_NPB_W#Z",
"?IsExpired#IItem#core##QAE_N_K#Z",
"?IsArenaField#IRegion#core##QBE?B_NXZ",
"?CanAttackTarget#IPVPMgr#core##QBE_NPBVICharacter#2##Z"
};
char patches2[][64]
This is an array of arrays. The first dimension is determined automatically from the number of elements in the initializer. The second dimension is specified as being 64 chars.
Some of the string literals with which you initialize patches2 are longer than 64 characters in length. You need to increase the size to some value large enough to hold the largest C string in the initializer.
Well, the declaration for a single string looks like this:
const char* myString = "MyString";
What you probably want is an array of const char*s. You can change char patches2[][64] to const char* patches2[] (an array of pointers to const char).
The number of const char*s in patches2 can be calculated using sizeof():
const char* patches2[] = {"CreateMutexW", /* The rest... */ };
int numPatches = sizeof(patches2) / sizeof(const char*);
So if you add/remove some strings, you don't have to update the dimensions.
Related
This question already has answers here:
How to find the size of an array (from a pointer pointing to the first element array)?
(17 answers)
Closed 7 years ago.
I am having a difficult time obtaining the correct size of a string in order to satisfy strcpy_s. For example if I specify
char buffer = {0};
char *str1 = (char*)&buffer;
strcpy_s(str1,sizeof("This is a string\n"),"This is a string\n");
Then it will work as expected. If however I declare the following:
char buffer = {0};
char *str1 = (char*)&buffer;
const char* string1 = "This is a string.....";
strcpy_s(str1, ?????,string1);
If I use anything other than a literal in place of ????? it will fail with a memory exception, for example if I use std:strlen(str1), etc. Any size literal for ???? will work. Of course using a fixed literal is not acceptable.
This is a major re-edit of the original question and I apologise to the people who have answered to date. However none of the the answers below have worked.
"This is a string" is a character array. When you say sizeof(Array)/sizeof(type) it will give the size of the array
When you define the string as const char* then the sizeof(pointer) gives the size allocated for the pointer no the array size
const char* ptr = "This is a string\n";
std::cout<<sizeof("This is a string\n")<<std::endl; //==>18
std::cout<<sizeof(ptr)<<std::endl; //==>4
First of all, the second parameter is the size of the destination buffer, not the size of the source buffer.
so the correct way is:
char str1[100];
strcpy_s(str1, sizeof str1, "Whatever string");
or
int n = 100;
char *str1 = new char[n];
strcpy_s(str1, n, "whatever string");
For an array (first example) sizeof returns the size of the array.
For a pointer (second example) sizeof returns the size of the pointer (which is not what you want)
In your second example, string1 is of type const char*. sizeof will return the size of the pointer, rather than the length of the string literal you are pointing to.
The first example works because a string literal is a const char[], and sizeof will correctly return the length of the string (but with the null terminating character as well). It's only coincidental that this works because char is 1 byte. Do not use sizeof to get string lengths.
To make your second example work, try using std::strlen.
This question already has answers here:
How do I use arrays in C++?
(5 answers)
Closed 8 years ago.
I have an character array of the form
char x[]='asdasdadsadasdas';
int p = sizeof(x)/sizeof(*x)
gives me correct result but when I pass this as an argument in another function like
void X(char* a)
int i = sizeof(a)/sizeof(*a)
and I call it
X(x)
p and i are not equal.How is it possible ?
When the char array gets passed to a function accepting a char*, the array is said to 'decay' to a pointer. This conversion is automatic, and the length information which was previously statically available to the compiler is lost.
Possible solutions are:
Pass the size of the array as an additional parameter.
Make the char-Array 0-terminated (i.e., a string literal) and use strlen. This is the common ways of operating on strings in C and C++. However, this introduces runtime cost which is not strictly necessary. However it provides some convenience (same API for statically and dynamically sized strings) and error resilience (the length is always correct).
Use templates to capture the length of the array. This is explained here..
void X(char* a)
int i = sizeof(a)/sizeof(*a)
Here, a is a pointer and *a is a char. So sizeof(a) won't return the size of the array, but the size of the pointer to the first element in the array.
In order to find the length of the string (which isn't the same as "the size of the array"), you have a few options.
One, don't use a char* at all, but a std::string (may create a temporary):
void X (const std::string& s)
{
size_t i = s.length();
}
Two, scan the string for the null-terminator (linear complexity):
void X (const char* p)
{
size_t i = strlen (p);
}
Three, use a template (needlessly complex code):
template <size_t N> void X (const char (&arr)[N])
{
size_t i = N;
}
Each of the above has it's own set of cons. But this is all best avoided if you take a broader look at your program and see where you can make improvements. Here's one that stands out to me:
char x[]='asdasdadsadasdas';
C-style arrays present their own problems and are best avoided altogether. Instead of using a C-style array, use a tool from the StdLib designed for just this problem:
std::string x = "asdasdadsadasdas";
sizeof(char *)
Gives you the size of a pointer. Eight bytes on my system.
char x[] = "fred";
sizeof(x);
Returns 5. The size of the string with the null termination.
void x(char * c) {
sizeof (*c);
}
Returns the size of a a char.
This is true no matter what the length or original type of the array is passed to void x(). Note that sizeof() is evaluated at compile time. At compile time the compiler cannot normally know what length of array it's been passed. For a run-time evaluation of string length, as said above, use strlen if you actually want the strings length in characters. (Or a template - but that's probably a more unusual solution).
I am writing my own append function to append a dynamic character array of string array2 at the end of another dynamic character array of string array1, using a static char buffer[50]. But the compiler generates the following errors: [Error] incompatible types in assignment of 'char' to 'char[50]'. I have tried to figure out the problem, but I don't seem to find the solution. Your help will be very appreciated. I am using Dev-C++. The code is bellow.
#include <iostream>
using namespace std;
char *Appendstring(char *a, char *b) // will append b to the end of a
{
static char buffer[50];
char *p=buffer=*a++; //[Error] incompatible types in assignment of 'char' to 'char[50]'
//[Error] invalid conversion from 'char*' to 'char'[-fpermissive]
p--;
while(*p++=b++);
p--; //append
while(*p++=*c++);
return buffer;
}
int main ()
{
string str="Displaying: ";
string add=" Summer is coming";
Appendstring(str, add);
return 0;
}
There are multiple errors in your append function, the biggest ones are using an array as a pointer and using a static buffer to merge strings. With a static buffer in place, all your merged strings will be in the same space, so merging two strings and then merging the other two would overwrite the results of the first merge!
You can change your function as follows:
char *Appendstring(const char *a, const char *b) // will append b to the end of a
{
char *buffer = new char[strlen(a)+strlen(b)+1];
char *p=buffer;
while(*p++=*a++); // Copy a into buffer
while(*p++=*b++); // Copy b into buffer right after a
*p=0; // Null-terminate the string
return buffer;
}
Of course the caller is responsible for freeing the results of Appendstring now.
You cannot assign into an array, which is what you do in buffer=*a++. what you meant is probably
static char buffer[50];
char *p=buffer;
*p=*a++;
In addition, here
p--;
while(*p++=*b++);
you are trying to derefence a pointer one element before the beginning of an array - which leads to undefined behaviour.
Moreover, nowhere do you check for the strings' length, so it can easily be more the 49 together and your code will be both incorrect and insecure (easy victim for buffer overflow attacks).
One last problem is that your code is non reentrant in any way, due to the use of static array. you can simply use simple array, if you don't want to adjust it to the strings' length, or allocate it dynamically, as was suggested here.
The best solution of course is to use std::string and forget all these problems.
I'm trying to parse a simple string to an array of *char and for some reason when I use string.c_str() it puts the entire string into *char[0] and the rest of the array is left blank (I originally thought that chars could only hold one ASCII character but I guess that they act differently as pointers), could anyone have a scan through my function and tell me if there are any obvious mistakes?
static void SetGame()
{
// Variable Initiation
int myRandom = rand() % (numOfWords - 1);
lengthOfString = wordArray[myRandom].length();
// Reinitiate Pointer Arrays
stringArray = new string[lengthOfString];
isDiscoveredArray = new bool[lengthOfString];
// Parse string to the array of characters
*stringArray = wordArray[myRandom].c_str();
// Set each boolean array value to false
for (int i = 0; i < sizeof(isDiscoveredArray); i++)
{
isDiscoveredArray[i] = false;
}
}
Here are my decelerations of the pointers
// Global Variable and pointer Declerations
string *wordArray;
int numOfWords;
string *stringArray;
int lengthOfString;
bool *isDiscoveredArray;
Any ideas? Thanks.
You are mixing types here. First you build an array of strings and store it in a pointer, then you assign to the first element a const char* coming from c_str. The code you currently have would be if your were creating a string for every character in your selected word.
Make your "stringArray" a const char* to fit with the code you already have, but remove the memory allocation.
You've got an array of std::string and when you deference it (i.e. *stringArray) its the same as stringArray[0], so that is why it always going into the first element of your array.
Since you are setting your array have the same number of elements as the string your are copying has characters, you may just want to use a string rather than a string array to copy it into.
If it supposed to be char* (character array) then you will need to explicitly copy the source, which is the result of wordArray[myRandom].c_str(), into your character array rather than using simple assignment.
I was working with a program that uses a function to set a new value in the registry, I used a const char * to get the value. However, the size of the value is only four bytes. I've tried to use std::string as a parameter instead, it didn't work.
I have a small example to show you what I'm talking about, and rather than solving my problem with the function I'd like to know the reason it does this.
#include <iostream>
void test(const char * input)
{
std::cout << input;
std::cout << "\n" << sizeof("THIS IS A TEST") << "\n" << sizeof(input) << "\n";
/* The code above prints out the size of an explicit string (THIS IS A TEST), which is 15. */
/* It then prints out the size of input, which is 4.*/
int sum = 0;
for(int i = 0; i < 15; i++) //Printed out each character, added the size of each to sum and printed it out.
//The result was 15.
{
sum += sizeof(input[i]);
std::cout << input[i];
}
std::cout << "\n" << sum;
}
int main(int argc, char * argv[])
{
test("THIS IS A TEST");
std::cin.get();
return 0;
}
Output:
THIS IS A TEST
15
4
THIS IS A TEST
15
What's the correct way to get string parameters? Do I have to loop through the whole array of characters and print each to a string (the value in the registry was only the first four bytes of the char)? Or can I use std::string as a parameter instead?
I wasn't sure if this was SO material, but I decided to post here as I consider this to be one of my best sources for programming related information.
sizeof(input) is the size of a const char* What you want is strlen(input) + 1
sizeof("THIS IS A TEST") is size of a const char[]. sizeof gives the size of the array when passed an array type which is why it is 15 .
For std::string use length()
sizeof gives a size based on the type you give it as a parameter. If you use the name of a variable, sizeof still only bases its result on the type of that variable. In the case of char *whatever, it's telling you the size of a pointer to char, not the size of the zero-terminated buffer it's point at. If you want the latter, you can use strlen instead. Note that strlen tells you the length of the content of the string, not including the terminating '\0'. As such, if (for example) you want to allocate space to duplicate a string, you need to add 1 to the result to tell you the total space occupied by the string.
Yes, as a rule in C++ you normally want to use std::string instead of pointers to char. In this case, you can use your_string.size() (or, equivalently, your_string.length()).
std::string is a C++ object, which cannot be passed to most APIs. Most API's take char* as you noticed, which is very different from a std::string. However, since this is a common need, std::string has a function for that: c_str.
std::string input;
const char* ptr = input.c_str(); //note, is const
In C++11, it is now also safe-ish to do this:
char* ptr = &input[0]; //nonconst
and you can alter the characters, but the size is fixed, and the pointer is invalidated if you call any mutating member of the std::string.
As for the code you posted, "THIS IS A TEST" has the type of const char[15], which has a size of 15 bytes. The char* input however, has a type char* (obviously), which has a size of 4 on your system. (Might be other sizes on other systems)
To find the size of a c-string pointed at by a char* pointer, you can call strlen(...) if it is NULL-terminated. It will return the number of characters before the first NULL character.
If the registry you speak of is the Windows registry, it may be an issue of Unicode vs. ASCII.
Modern Windows stores almost all strings as Unicode, which uses 2 bytes per character.
If you try to put a Unicode string into an std::string, it may be getting a 0 (null), which some implementations of string classes treat as "end of string."
You may try using a std::wstring (wide string) or vector< wchar_t > (wide character type). These can store strings of two-byte characters.
sizeof() is also not giving you the value you may think it is giving you. Your system probably runs 32-bit Windows -- that "4" value is the size of the pointer to the first character of that string.
If this doesn't help, please post the specific results that occur when you use std::string or std::wstring (more than saying that it doesn't work).
To put it simply, the size of a const char * != the size of a const char[] (if they are equal, it's by coincidence). The former is a pointer. A pointer, in the case of your system, is 4 bytes REGARDLESS of the datatype. It could be int, char, float, whatever. This is because a pointer is always a memory address, and is numeric. Print out the value of your pointer and you'll see it's actually 4 bytes. const char[] now, is the array itself and will return the length of the array when requested.