In C++, what's the difference between this:
char example[10];
and this:
char* example = new char[10];
in both cases, I'm not initializing the content of the arrays, but just wanting to get 10-bytes in memory allocated to the character array. In both cases, I intend to then use sprintf() to assign a string value to them with no intermediate step.
This:
char example[10];
Declares example as an array of char containing 10 elements. If declared at file scope, this array will typically reside in the data segment, while if it is declared at block scope it will typically reside on the stack.
In contrast, this:
char* example = new char[10];
Declares example as a pointer to char, and initializes it with a pointer to dynamically allocated memory which points to the first member of a 10 member array of char. This dynamically allocated memory typically resides on the heap.
Note also that new is specific to C++.
char example[10];
example is an array of 10 chars. Depending on context, it has automatic or static storage. The size can only be compile time constant. The array is destroyed and deallocated automatically.
char* example = new char[10];
example is a pointer. It is not an array. It points to first element of an array in dynamic storage. The size of dynamic array can be determined at runtime. The array is not destroyed and deallocated automatically. If not deallocated, the memory will leak.
Dynamic allocation is generally slower than static or automatic. On the other hand, the amount of memory available for automatic storage is typically very limited.
Bare owning pointers should be avoided. Best practice is to use a smart pointer or a RAII container such as std::vector when dynamic array is needed.
The main difference is that, in your first example you are have to already know at declare this char array his size, but in your second example, you are declare char array with pointer, which points on some value. That means you can only declare some char pointer without knowing the size of the char array. It is very usefull for programs, where the user has to write his nickname as input, maximal lenght of nickname can be 10 characters, but it can be less then 10 characters, that means you have to use pointers for dynamic allocating memory so as not to use too much unused memory.
For example:
int main()
{
char nm[10]; //Create char array, where you will save an input
char* nickname; //Declare pointer
std::cout << "Nickname: " << std::endl;
fflush(stdin);
gets(nm); //Save input
// Here we go find the size of used memory in char array nm
int size_of_nm = 0;
for (char i : nnnn)
{
if (i == '\0') //If char i is equal to zero character, we find the size of used
{ //memory in char array nm
break;
}
else //If i is not equal to zero character, we do not find the size of used
{ //memory in char array nm and loop will continue
size_of_nm++; //Size counter plus one
}
}
nickname = new char[size_of_nm + 1]; //Create new pointer on char array and set the
//size of used memory in char array
//plus one, because the char array is always
//ending with zero character
}
But I recommend using a strings. It is more safer, because you dont have to know the size of used memory, memory of string is allocated automatically.
Related
I am recreating the string class using char arrays. My problem is, when I allocate memory for a larger array, it generates an array that is completely the wrong size.
For example:
int allocated = 4;
char * reservedString = new char[allocated];
cout << strlen(reservedString);
Instead of creating a character array of size 4, reservedString points to a character array with 14 spots containing random characters.
This is what the debug shows me. Reserved string is now the wrong size with a bunch of random characters in it. When I try to use strcpy or strcpy_s it is writing memory out of bounds because the new array sizes are wrong.
How can I create a char array with an unknown length, which is provided by a variable, that is right size.
I can not use the std::string class or std::vector.
When you are creating an object with the new operator, your data remains not initialized. The code you provide is basically an array of bytes.
The documentation about strlen says:
computes the length of the string str up to, but not including the terminating null character.
There is no null terminator here.
You should do:
int allocated = 4;
char * reservedString = new char[allocated]();
This will initialize your array and set all the elements to \0
strlen expects a null-terminated string, which means a string that ends in a null character (\0). You're passing to it a pointer pointing to newly allocated memory, which contains uninitialized values and reading it causes undefined behavior. So when strlen searches for a null character in order to determine the length of the string, stuff is going to go wrong.
You cannot determine the size of an array given only a pointer to it unless you know it's going to be terminated by a null character or something similar. So either properly initialize the array with a null-terminated string or keep track of the length yourself.
This is my code
char *t = type1[j];
int ln = strlen(t);
char *s = new char[ln];
cout<<"ln "<<ln<<" s "<<strlen(s)<<endl;
When I run it:
Why are the lengths different?
When you dynamically allocate an array with new[], you get a pointer to an uninitialized block of memory. You can't call strlen on it, as that function expects a pointer to a character array that contains a null-terminated string. It works by reading each byte in the array until it finds a null byte and returning the count of how many bytes it read before it found a null byte. And since the array is uninitialized, calling strlen does make sense. In fact, it invokes undefined behavior.
There's no way to look at a dynamically allocated buffer and find out how big that buffer is. You need to keep track of the size of the buffer separately. Since you used new char[ln] to create the buffer, you know that you have a buffer large enough to hold ln variables of type char.
I want to create an array of chars (char path[size] = "") while getting "size" from user.
When I try something like this:
int size = getSizeFromUser();
char path[size] = "";
I get a warning says "expression must have a constant value".
How can I do it right?
Thanks a lot!
How can I do it right?
Variable length arrays aren't standard c++. The correct way to do it is to use a std::vector or a std::string instead of a raw array:
int size = getSizeFromUser();
std::string path(size,'\0');
In order to create a table with the users size you have to allocate your memory on the heap
int size = 4;
char *path = new char[size];
after using your array you have to manually delete it from the heap
delete path;
If you declare char path[size]; then size has to be known at compile time. You read it at runtime so you need to use dynamic memory allocation, like char* path = new char[size]; and when you are finished call delete []path;.
If you want this to be a string with size visible characters, please consider that C-strings are null-terminated, meaning that you would have to reserve one extra char at the end of the array and set it to 0.
A better solution for a C++ program would probably be to use a std::string instead of a char*.
When creating an array, its size must be constant.
If you want a dynamically sized array, you will have to allocate memory for it and you'll also need to free it when you're done with it.
To simply all these its always nice to use std::string
In below code example, memory for an integer is dynamically allocated and the value is copied to the new memory location.
main() {
int* c;
int name = 809;
c = new int(name);
cout<<*c;
}
But, when I try to do the same with a char string it doesn't work.
Why is this?
int main() {
char* p;
char name[] = "HelloWorld";
p = new char(name);
cout << p;
}
Your second example doesn't work, because char arrays work differently than integer variables. While single variables can be constructed this way, this doesn't work with (raw) arrays of variables. (As you have observed.)
In C++ you should try to avoid handling pointers and raw arrays as much as you can. Instead, you'd rather use the standard library containers to take a copy of that string to an array of dynamically allocated memory. std::string and std::vector<char> are especially suitable in this case. (Which one should be preferred depends a bit on the semantics, but probably it's the std::string.)
Here's an example:
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
int main(){
char name[] = "Hello World";
// copy to a std::string
std::string s(name);
std::cout << s << '\n';
// copy to a std::vector<char>
// using strlen(name)+1 instead of sizeof(name) because of array decay
// which doesn't occur here, but might be relevant in real world code
// for further reading: https://stackoverflow.com/q/1461432
// note that strlen complexity is linear in the length of the string while
// sizeof is constant (determined at compile time)
std::vector<char> v(name, name+strlen(name)+1);
std::cout << &v[0] << '\n';
}
The output is:
$ g++ test.cc && ./a.out
Hello World
Hello World
For reference:
http://en.cppreference.com/w/cpp/string/basic_string
http://en.cppreference.com/w/cpp/container/vector
Your second code snippet does not work because new int(name) initializes an int from an int, while new char(name) tries to initialize a char from a char[11] array.
There is no array constructor taking an array in C++. In order to make a copy of an array, you must allocate an array, and then copy data into it:
p = new char[sizeof(name)];
std::memcpy(p, name, sizeof(name));
In the first case you allocate memory for a single int object, and initialize with a single int value. Great, this works.
In the second case you allocate memory for a single char object, and initialize it with an array of characters. It does not work, an array of objects does not fit in a memory of a single object. Besides, the array has a different type, so the initialization is ill-formed.
To allocate memory for an array of characters (such as a string), you can use new[]:
char* ptr = new char[11]{"HelloWorld"};
PS. The GNU compiler (until the current version 7 at least) and clang (until version 4) have a bug which breaks the above initialization. A workaround is to copy the string after allocation.
PPS. While it is useful to learn these things, don't do manual memory management in actual programs. Use RAII containers such as std::string for strings and std::unique_ptr for single dynamic objects.
Your code doesn't work as you are trying to initialize a char instead of array of characters. In order to dynamically allocate memory, you need to allocate the memory and then copy over the content.
p = new char[strlen(name) +1];
std::strcpy(p, name);
Though string is dynamic so it will not have any definite size so when i get s[1] before s[0] how C++ will calculate its offset address.
For example int a[2]
0000:1000 a[0]
0000:1004 a[1]
Program:
#include<iostream>
#include<vector>
using namespace std;
int main()
{
string s[2];
cin>>s[1];
cout<<s[1]<<endl;
cin>>s[0];
cout<<s[0]<<endl;
}
An array of strings is an array of string objects, which are of fixed size and effectively contain pointers elsewhere where the strings actually reside.
std::string does not in its memory layout actually contain its characters. It simply contains a pointer to a dynamically allocated memory and keeps track of its size. Just like std::vector doesn't actually store its elements inside its members. Instead, it has a pointer to the actual elements situated "on the heap". S
So regardless of the number of characters a string has, its size (meaning sizeof (std::string) )is a compile time constant.