Is size of an array flexible in C++? - c++

After declaring a character array, say char s[20], and eventually getting inputs using cin.getline(s,100) change the size of the array to 100, change (exactly) to the number of characters entered as input, or does it change at all? What happens to the array size that I initially declared?
I'm new to programming, so your simple explanation will be greatly appreciated. Thank you!

The size does not change what happens is that you are writing past the buffer size. If you write far enough through the buffer you will end up causing a buffer overflow.
You should use std::vector whenever you can instead of c-style arrays.
As Ted Lyngmo commented, in this case std::string will be better to use than std::vector or the c-style array:
std::string input;
std::getline(std::cin, input);

The answer is: No.
The size of the character array s doesn't changes to 100, but when you exceed the limit of the array's length, you cause a buffer overflow, which is really bad.
Let's consider an incorrect program, which is based on your assumption:
#include <iostream>
int main(void) {
char s[20];
std::cout << "Enter a sentence: ";
std::cin.getline(s, 100);
std::cout << s << std::endl;
return 0;
}
Here I just try to expand the size of array s, it actually doesn't.
If you enter an example sentence, like: hello-world-how-are-you-today (which contains 29 characters including a null-terminator), it'll just store:
hello-world-how-are-
And notice that it doesn't contains a null-terminator since all the containers are used and it just keeps reading which may cause undefined behavior (UB).

Arrays don't have dynamic memory. If you want dynamic memory allocation, you can use std::string for an array of characters, or std::vector.
std::string works like char s[x];, but it is more flexible and it has a few different things.
std::vector is basically like an array, but you can add / remove elements.
Syntax:
std::vector<type> name; // this is the classic syntax, I won't get more in-depth
Example:
std::vector<int> myVect;
You can add elements using myVect.insert(position, element); or something similar, I don't remember exactly, or you can use myVect.push_back(element); to add an element at the end of the vector.
Search it on cplusplus reference or GeeksForGeeks, you'll find a lot of information.

C++ doesn't have a variable-length array.
To handle this situation, you can have below data structures.
std::string
std::vector
dynamic array, using new[] in C++ or malloc() in C.
Click on the links, and you will find the description and usages.

Related

storing a c++ string into a char* vector

I'm trying to store this string into a vector of pointers. This is just the starting point of the code. Eventually the vector will store words the user types in and either add it to the vector if the vector doesn't have it or show the word is already in the vector.
I tried to use strcpy() but then it told me to use strcpy_s(). So I did now and now it just crashes every time with no error. Can someone give me some insight into what is going on here.
vector<char*> wordBank;
string str;
cin >> str;
wordBank[0] = new char[str.length() + 1];
strcpy_s(wordBank[0], str.length() + 1 , str.c_str() );
cout << wordBank[0];
delete[] wordBank[0];
I would not consider vector<char*> wordBank; this c++ code, but rather C code that happens to use some C++ features.
The standard library in C++ can make your life easier. You should use std::vector<std::string> instead.
vector<string> wordBank;
wordBank.push_back(str);
It avoid all the pointer stuff, so you need not to do memory management (which is a good reason get rid of the pointers).
For strcpy_s, it's a safer version of strcpy, because you have to explicitly specify the size of the target buffer, which can avoid buffer overflows during copies.
However, strcpy_s is non-standard and MS specific, NEVER use strcpy_s unless your just want your code compiled on MSVS. Use std::copy instead.
The default size of a vector is 0
Hence this line
vector<char*> wordBank;
just defines a 0 sized vector of character pointers
As people have mentioned in comments you can go with either of these 2 options:-
vector<char*> wordBank(1);
OR
wordBank.push_back(...);
You don't need char* elements in the vector. You can use string instead, and append your strings to the vector with push_back(), which will allocate the needed space:
vector<string> wordBank;
string str;
cin >> str;
wordBank.push_back(str);
cout << wordBank[0];
This will free you from the burden of having to use delete every time you want to remove a string from the vector. Basically, you should never have to use delete on anything, and to accomplish that, you should avoid allocating memory with new. In this case, that means avoiding the use of new char[/*...*/], which in turn means you should use string to store strings.
vector<char*> wordBank; constructs an empty vector. As such, wordBank[0], which uses operator[], has undefined behavior since you're accessing out of bounds.
Returns a reference to the element at specified location pos. No bounds checking is performed.
You can use push_back to add a new element, as such:
wordBank.push_back(new char[str.length + 1]);
Of course the most sensible thing is to just use use a vector of strings
vector<string> wordBank;
wordBank.push_back(str);
You're trying to manually manage memory for your strings, while the std::string class was designed to do that for you.
Also, from what you are describing your use case to be, you may wish to check out std::map and/or std::set. Here's a tutorial.

Length of pointer to pointer

I searched and I didn't find anything that is like my situation. I have a float** and well I know that it is a special type of pointer because it is an array of elements that have a float* that points to another zone of memory. So I write a simple code to detect the length of this matrix, to be more precise the length of the float + elements inside float**; But it results in a segmentation fault.
Here there is my code:
int Loader:: Length(float** length)
{
int count=0;
while(*length[count]!='\0'){
count++;
}
std::cout<<count<<std::endl;
return count;
}
Sorry for my english and sorry for the stupid question. Thanks to all.
I have a float** and well I know that it is a special type of pointer
Not really. A double pointer is just a special case of a single pointer. It is still a pointer to T, and that T happens to be float*.
because it is an array of elements
No! It is not an array. It may point to the first element of an array.
that have a float* that points to another zone of memory.
So, more precisely, a float** may point to the first element of an array full of float*. Where those individual float*s point to is another story.
So I write a simple code to detect the length of this matrix,
You cannot. When all you have is a pointer to the beginning of an array, then the size information is already lost.
That is, unless you have a convention for the last element, like C-style strings or string literals with their '\0' terminator. Which brings us to the next point...
int Loader:: Length(float** length)
{
int count=0;
while(*length[count]!='\0'){
Here's the culprit. Not all arrays are terminated by '\0'. In fact, it's not typical at all for arbitrary arrays containing a zero separator.
So unless the array to whose first element length points to actually contains an element which compares to '\0', then your loop will go one element past the end of the array and try to read from there. In that very moment, undefined behaviour is invoked and your program can do anything, including random crashes.
The best solution to your problem is to use std::vector, because a std::vector always knows its own size. So make it std::vector<float*>. Or better yet, a std::vector<std::vector<float>>.
In fact, if it's really a matrix, then make it std::vector<float>, store all contents contiguously, additionally store the matrix' width somewhere, and always calculate the offset for X/Y.
The problem is caused by your expectation that all arrays operate in the same way as literal character strings, ie that they are automatically terminated by a 0 value. Neither C++ or C work that way.
If you want the array length you need to do one of the following:
Pass the length along with the array everywhere.
Use a std::vector, std::deque or std::array instead of an array, and get the length from that.

Dynamically allocated strings in C

I was doing a relatively simple string problem in UVa's online judge to practice with strings since I've been having a hard time with them in C. The problem basically asks to check if a string B contains another string A if you remove the 'clutter' and concatenate the remaining characters, for example if "ABC" is contained in "AjdhfmajBsjhfhC" which in this case is true.
So, my question is how can I efficiently allocate memory for a string which I don't know its length? What I did was to make a string really big char Mstring[100000], read from input and then use strlen(Mstring) to copy the string the a properly sized char array. Something like :
char Mstring[100000];
scanf("%s",Mstring);
int length = strlen(Mstring);
char input[length+1]={0};
for(int i = 0; i<length;i++){
input[i]=Mstring[i];
}
Is there a better/standard way to do this in C? I know that C does not has a great support for strings, if there is not a better way to do it in C maybe in C++?
If you have the option of using C++ (as you mentioned), that is going to make your life a lot easier. You can then use a STL string (std::string) which manages dynamically sized strings for you. You can also drop the old scanf() beast and use std::cin.
Example:
#include <iostream>
#include <string>
void main()
{
std::string sInput;
std::getline(std::cin, sInput);
// alternatively, you could execute this line instead:
// std::cin >> sInput;
// but that will tokenize input based on whitespace, so you
// will only get one word at a time rather than an entire line
}
Describing how to manage strings that can grow dynamically in C will take considerably more explanation and care, and it sounds like you really don't need that. If so, however, here is a starting point: http://www.strchr.com/dynamic_arrays.

array of ifstream objects in C++

I am trying to create an array of ifstream objects, the code compiles and I am able to create the array of ifstream objects of size sizeargs-1 however once I try to open a file in one of the ifstream objects the program crashes, it's very frustrating.
the reason I am trying it this was is that I have to dynamically create ifstream objects based on the number of .ppm files in memory and this seemed like the perfect solution, just being able to ifstream_array[1].open(args[0]); since I need to read text from multiple .ppm files simultaneously.
If doing this is impossible; is there an alternative way of doing it?
int main(int argc, char ** args)
{
//counts number of .ppm files in array
int sizeargs = (sizeof(args)/sizeof(*args));
ifstream inputfiles[sizeargs-1];
int incounter = 0;
//this is where the program crashes
inputfiles[incounter].open(args[0]);
}
int sizeargs = (sizeof(args)/sizeof(*args)); //counts number of .ppm files in array
No, it doesn't. This evaluates to sizeof(char**) / sizeof(char*), which is always 1. sizeargs-1 is thus 0 and you have no items in your array. You cannot find the size of an array via a pointer to it. You need to use argc, which is the number of elements in args.
Based on the comments, you should also avoid variable length arrays, as they are availabe only with compiler extensions and are not part of the C++ standard. I would recommend using a vector instead:
std::vector<std::ifstream> inputfiles(sizeargs-1);
This statement:
int sizeargs = (sizeof(args)/sizeof(*args)); //counts number of .ppm files in array
will always yield sizeargs = 1 on *a modern compiler, since the size of a basic data pointer divided by the size of a basic data pointer, is 1.
In C++11 and earlier this statement:
ifstream inputfiles[sizeargs-1];
is invalid, since the size of a (not dynamically allocated) raw array must be a compile time constant.
However, g++ offers C99 variable length arrays (VLAs) as a language extension.
Instead, use a std::vector.
* As James Kanze points out in a comment to another answer, there have been machines where sizeof(char*) was larger than sizeof(char**). Since char is the basic addressable unit, a char* pointer is the largest ordinary pointer. I didn't think that distinction would be relevant here, but reading James' comment (and we have discussed this in the past), I realized that my attitude to the "worth" of an SO answer, is wrong, and adjusted accordingly.

C++ Char without Limit

I'm pretty well versed in C#, but I decided it would be a good idea to learn C++ as well. The only thing I can't figure out is chars. I know you can use the string lib but I also want to figure out chars.
I know you can set a char with a limit like this:
#include <iostream>
using namespace std;
int main()
{
char c[128] = "limited to 128";
cout << c << endl;
system("pause");
return 0;
}
But how would I make a char without a limit? I've seen chars with * but I though that was for pointers. Any help is greatly appreciated.
You can't have an array without limit. An array occupies space in memory, and sadly there is no such thing as limitless memory.
Basically, you have to create an array of a certain size and write logic to expand the size of the array as you need more space (and possibly shrink it as you need less space).
This is what std::string and std::vector do under the hood for you.
You can use a vector of char.
std::string being a nice implementation of a vector of chars :)
A datastructure needs memory allocated for it.
Some datastructures (such as string, or a vector of chars) have internal logic in their class which allocates memory as needed dynamically.
Arrays (which come from C) do not - you need to allocate memory for them manually, by either static way (char c[128]) as your example does, or dynamically at runtime via malloc() and company. Of course, to do the dynamic allocation/reallocation right is not very simple and why bother doing it when there already are classes (e.g. string) that do it for you the right way? :)
C/C++ char arrays are just about identical to char*. The same block of code can be rewritten as:
int main()
{
char* c = "limited to 128";
cout << c << endl;
system("pause");
return 0;
}
The compiler will generate a null terminated string for you that you could use throughout your code. The way to do it dynamically would be to either use malloc or operator new [].
char* str = malloc(sieof(char) * requiredlength); //C-compatible
OR
char* str = new char[requiredlength];