13 Replies - 396 Views - Last Post: 07 December 2017 - 12:51 PM Rate Topic: -----

#1 Rixterz   User is offline

  • D.I.C Head

Reputation: -7
  • View blog
  • Posts: 163
  • Joined: 26-August 12

Calculating correct length for char[]

Posted 07 December 2017 - 10:08 AM

Hi

I've written a method to simplify MessageBox which would display text in the format "Value of something: " + (a variable).

To do this, I have this code:

str is passed for example "Value of something: %s"
var is passed using, for example std::to_string(myInt);

void DebugUtils::msgbox(const char* title, const char* str, const std::string var)
{
	const char* var_str = ConversionUtils::stringToChar(var); // convert var to char* using std::string#c_str()
	const int len = sizeof(str) + sizeof(var);		  // calculate length of string and var
	char buff[len];						  // create perfectly-sized buffer
	
	sprintf_s(buff, len, str, var);				  // write values into buffer

	MessageBox(0, buff, title, MB_OK);			  // error: buffer too small
}



Originally, my code removed the %s in the length calculation as this isn't the true length of the string;

> "Hello %s", "name"
len 8, 4 -> 12

"Hello name" -> length 10

If it affects anything, I'm using Multi-Byte encoding.

This post has been edited by Rixterz: 07 December 2017 - 10:10 AM


Is This A Good Question/Topic? 0
  • +

Replies To: Calculating correct length for char[]

#2 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 6166
  • View blog
  • Posts: 21,268
  • Joined: 05-May 12

Re: Calculating correct length for char[]

Posted 07 December 2017 - 10:39 AM

sizeof() returns the number of bytes physically used by a variable or type. It doesn't interrogate a class instance to see how much space it really is taking.

So sizeof(str) is either 4 or 8 depending on whether you have 32 or 64 bit pointers, and sizeof(var) is dependent on what STL implementation you have and what kind of space overhead std::string has. On my VS2017 installation, x86 Debug builds have sizeof(std::string) at 28 bytes, and Release builds at 24 bytes.

To find out the length of a std::string, you simply call the length() member. To find out the length of a C string, you use strlen().

Your perfectly sized buffer above is not perfect. It seems to forget about the null terminator that C and C++ uses for its strings.
Was This Post Helpful? 0
  • +
  • -

#3 Radius Nightly   User is offline

  • D.I.C Regular

Reputation: 31
  • View blog
  • Posts: 291
  • Joined: 07-May 15

Re: Calculating correct length for char[]

Posted 07 December 2017 - 10:45 AM

View PostRixterz, on 07 December 2017 - 06:08 PM, said:

my code removed the %s in the length calculation as this isn't the true length of the string;

View PostRixterz, on 07 December 2017 - 06:08 PM, said:

> "Hello %s", "name"
len 8, 4 -> 12

Hello %s
12345678
name
1234

8 and 4, 12?

View PostRixterz, on 07 December 2017 - 06:08 PM, said:

"Hello name" -> length 10

Hello name
1234567890


Length are, 10?

So it works fine. If %s are some variable, dont put it in "", but outside, so he dont print %s as is, but its variable... if its still part of a length calculation, it will be in count.

This post has been edited by Radius Nightly: 07 December 2017 - 10:48 AM

Was This Post Helpful? 0
  • +
  • -

#4 jimblumberg   User is online

  • member icon

Reputation: 5471
  • View blog
  • Posts: 17,023
  • Joined: 25-December 09

Re: Calculating correct length for char[]

Posted 07 December 2017 - 10:49 AM

I see several problems with your code.

First you're using sizeof() on pointers. This will only get you the number of bytes that a pointer occupies in memory, not the length of the C-strings. Use strlen() to get the length of a C-string.

Second you're attempting to use sizeof() on a string, this will only get you the number of bytes that a string occupies in memory, not the length of the string. Use yourStringName.length() to get the length of a C++ string.

Third be careful arrays in C++ require compile time constants.

Forth your buffer size will not be large enough to hold your combined strings, you need to account for the mandatory end of string character which every C-string requires.

Fifth sprintf() has no idea how to handle a C++ string. If you're going to use sprintf() you really should find and study the documentation for this function. But I really suggest you consider using stringstreams instead.

I really suggest you consider using C++ strings instead of the C-strings:



Perhaps something more like this:

void DebugUtils::msgbox(const std::string& title, const std::string& str, const std::string& var)
{
    std::string buffer = str + " " + var;
    MessageBox(0, buffer.c_str(), title.c_str(), MB_OK); 
}



Jim
Was This Post Helpful? 0
  • +
  • -

#5 Rixterz   User is offline

  • D.I.C Head

Reputation: -7
  • View blog
  • Posts: 163
  • Joined: 26-August 12

Re: Calculating correct length for char[]

Posted 07 December 2017 - 10:50 AM

I've changed it to the following, but I'm getting an error;

const size_t len = strlen(str) + var.length();
char buff[len]; <-- error



expression must have a constant value
Was This Post Helpful? 0
  • +
  • -

#6 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 6166
  • View blog
  • Posts: 21,268
  • Joined: 05-May 12

Re: Calculating correct length for char[]

Posted 07 December 2017 - 11:01 AM

That is because Visual Studio C++ follows the C++ standard and does not support the use of VLAs. You are likely finding sample code on the Internet that uses GCC which allows the use of VLAs.

At this point, based on the flavor of questions you have recently been asking, I highly suggest that you set aside this game project for a while, and go through a crash course to learn C++. Pick up something like a "Learn C++ in 30 days" type book. Since you already know C#, some of the programming concepts will be familiar and you'll just need to focus on the language (unlike others who are both trying to learn the language as well as learning how to program). Very likely, you'll burn through the book in less than 14 days. Take time to do the exercises though even if you skip entire sections of a chapter. It'll help reinforce your learning.
Was This Post Helpful? 0
  • +
  • -

#7 snoopy11   User is offline

  • Engineering ● Software
  • member icon

Reputation: 1460
  • View blog
  • Posts: 4,726
  • Joined: 20-March 10

Re: Calculating correct length for char[]

Posted 07 December 2017 - 11:02 AM

If you insist on using c-strings instead of std::string or if you are writing a C program...

then you would have to dynamically allocate memory

in C++ it would be

char* buff = new char[len];


in C it would be

char* buff = malloc(len*sizeof(char));


then using delete[] for C++
and free for C respectively once you are done with the memory ie you are no longer using it.
Was This Post Helpful? 0
  • +
  • -

#8 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 6166
  • View blog
  • Posts: 21,268
  • Joined: 05-May 12

Re: Calculating correct length for char[]

Posted 07 December 2017 - 11:10 AM

View PostRixterz, on 07 December 2017 - 12:50 PM, said:

I've changed it to the following, but I'm getting an error;

const size_t len = strlen(str) + var.length();
char buff[len]; <-- error



expression must have a constant value


And if you ask, why does this work:
const int len = sizeof(str) + sizeof(var);
char buff[len];


but you code using the correct way of getting the length does not, here's the answer: The compiler can determine the sizeof() objects at compile time, so the compiler knows how much space to allocate on the stack for buff. In the other case, the compiler has no idea how much space to allocate on the stack for buff. This is where VLAs come in, and Microsoft bails out. :)
Was This Post Helpful? 0
  • +
  • -

#9 jimblumberg   User is online

  • member icon

Reputation: 5471
  • View blog
  • Posts: 17,023
  • Joined: 25-December 09

Re: Calculating correct length for char[]

Posted 07 December 2017 - 11:13 AM

Quote

I've changed it to the following, but I'm getting an error;

As already explained C++ requires compile time constants, strlen() and std::string.length() are runtime functions so do not create compile time constants.

The reason your first snippets appeared to work is because the sizeof() operator is a compile time operator which is capable of satisfying the compile time requirement for arrays. However you can only use sizeof() to get the size of the array is when the actual array is in scope. Since you passed the array into a function the actual array is not in scope. Remember that when you pass an array into a function the array decays to a pointer, so all you see in that function is a pointer not an array.

Edit:

Quote

This is where VLAs come in, and Microsoft bails out.

A properly configured gcc compiler will also issue an error diagnostic. Never use your compiler without properly configuring the warning levels. Most compilers, by default, issue few diagnostics.


Jim

This post has been edited by jimblumberg: 07 December 2017 - 11:15 AM

Was This Post Helpful? 2
  • +
  • -

#10 Rixterz   User is offline

  • D.I.C Head

Reputation: -7
  • View blog
  • Posts: 163
  • Joined: 26-August 12

Re: Calculating correct length for char[]

Posted 07 December 2017 - 11:36 AM

The following now works, but what's the difference between this and having '&' after each std::string parameter?

void DebugUtils::msgbox(const std::string title, const std::string str, const std::string var)
{
	MessageBox(0, (str + " " + var).c_str(), title.c_str(), MB_OK);
}


Was This Post Helpful? 0
  • +
  • -

#11 jimblumberg   User is online

  • member icon

Reputation: 5471
  • View blog
  • Posts: 17,023
  • Joined: 25-December 09

Re: Calculating correct length for char[]

Posted 07 December 2017 - 11:50 AM

Quote

The following now works, but what's the difference between this and having '&' after each std::string parameter?


In C++ there are three ways of passing variables into functions, pass by value (the default mechanism), pass by reference (this is what the ampersand means in this content), and pass by pointer.

When passing by value the compiler creates a copy of the variable and passes this copy into the function. All modifications to the parameter are local to the function, any changes are lost when the function returns. When dealing with C++ classes like std::string this copy operation can take a bit of time so you will usually want to pass by reference instead to avoid this copy.

When passing by reference the compiler creates an alias (the address of the variable) and passes this alias into the function. All modifications to the parameter are reflected in the variable in the calling function.

When passing by pointer the compiler creates a copy of the address of the variable and passes this address to the function, by properly de-referencing the pointer you can modify the value of the variable in the calling function.

The const qualifier prevents you from modifying that variable in the function.


Jim

This post has been edited by jimblumberg: 07 December 2017 - 11:52 AM

Was This Post Helpful? 0
  • +
  • -

#12 Rixterz   User is offline

  • D.I.C Head

Reputation: -7
  • View blog
  • Posts: 163
  • Joined: 26-August 12

Re: Calculating correct length for char[]

Posted 07 December 2017 - 12:25 PM

So I imagine the benefits of passing by reference over pointer are;

1) You don't have to delete the pointer later
2) You can directly manipulate the variable instead of dereferencing it, which I imagine is slightly more efficient
Was This Post Helpful? 0
  • +
  • -

#13 jimblumberg   User is online

  • member icon

Reputation: 5471
  • View blog
  • Posts: 17,023
  • Joined: 25-December 09

Re: Calculating correct length for char[]

Posted 07 December 2017 - 12:50 PM

Quote

1) You don't have to delete the pointer later

No, the only time you need to use delete is when you use new and usually you don't need new in order to pass a pointer into a function (another use of the multi-faceted ampersand).

Quote

2) You can directly manipulate the variable instead of dereferencing it, which I imagine is slightly more efficient

No, not really more efficient, just a lot less error prone and confusing.

You may want to study the function tutorials contained in my signature for more information.


Jim
Was This Post Helpful? 0
  • +
  • -

#14 snoopy11   User is offline

  • Engineering ● Software
  • member icon

Reputation: 1460
  • View blog
  • Posts: 4,726
  • Joined: 20-March 10

Re: Calculating correct length for char[]

Posted 07 December 2017 - 12:51 PM

Not really no....

If you are just writing a function then passing by reference would be more advisable.

If you are writing a class function then I would pass in a pointer as

1. References hide that you are changing data stored someplace else.
2. It's easy to confuse a Reference with a Copied object.


and Pointers make it obvious!
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1