Why does it skip array index 0 ?

Write your question here.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 #include <iostream>
using namespace std;

int main(){
int arraySize;
cout << "Enter the array size:";
cin >> arraySize;
string arr [arraySize];
for(int i=0; i<arraySize; i++){
cout << "Enter a string for array index "<<i<<':';
getline(cin,arr[i]);
}
}

This isn't valid C++ code. The size of arrays need to be determined at compile time - not run-time as here. Also, cin >> leaves the trailing \n in the buffer which is picked up by the getline() and treated as an input with no data. This 'dangling' \n left by cin needs to be removed.

Using a vector, consider:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <vector>
#include <string>
using namespace std;

int main()
{
	size_t arraySize {};

	cout << "Enter the array size: ";
	cin >> arraySize;

	std::vector<std::string> arr(arraySize);

	for (size_t i = 0; i < arraySize; ++i) {
		cout << "Enter a string for array index " << i << " : ";
		getline(cin >> ws, arr[i]);
	}

	for (const auto& a : arr)
		std::cout << a << '\n';
}



Enter the array size: 4
Enter a string for array index 0 : qwe
Enter a string for array index 1 : asd
Enter a string for array index 2 : zxc
Enter a string for array index 3 : poi
qwe
asd
zxc
poi



One way to get rid of the trailing '\n' in the buffer is to use cin.ignore();, that works for me. I'm not sure exactly what it does, but I know that it at least removes that trailing newline.

@seeplus is correct, this is not good programming practice, because 1: it dynamically allocates memory at run-time without requesting it, and 2: you can run into memory issues when you do that, particularly because you're using strings which also dynamically allocate memory. You're better off using a pointer to properly dynamically allocate the memory.
I will mention that my compiler doesn't give me any errors when compiling or running; however, it is a 12-year-old LLVM clang compiler.

For example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
int main (int argc, char const *argv[])
{
	int arraySize;
	
	// declare a pointer for dynamic allocation
	std::string* array;
	
	std::cout << "Enter the array size: ";
	std::cin >> arraySize;
	
	// clear the newline in the buffer
	std::cin.ignore ('\n');
	
	// request memory
	array = new std::string[arraySize];
	
	for (size_t i = 0; i < arraySize; ++i)
	{
		// I am displaying it with i + 1 because it is the first array element,
		// and it just makes it easier for the user, 
		// because if they see array element 0, they might get confused. 
		// This way it's just less confusing.
		std::cout << "Enter a string for array element " << i + 1 << ": ";
		getline (std::cin, array[i]);
	}
	
	for(size_t i = 0; i < arraySize; ++i)
	{
		std::cout << "Array element #" << i + 1 << ": " << array[i] << std::endl;
	}
	
	// This is to prevent your console from closing down immediately
	// If you don't have that problem, just delete this.
	std::cout << std::endl << "Press enter to exit...";
	std::cin.get();

        // Make sure you delete the allocated memory!
        delete [] array;
        array = nullptr; // nullptr means that the pointer doesn't point to anything.

	return 0;
}


Also, I (or rather my compiler) noticed that you forgot to return 0 at the end of the program.

Hope this helps!

Best,
max

Edit:
I added the delete [] to the program, in response to a comment by @keskiverto.
Last edited on
@agent max,

Have a look at https://en.cppreference.com/w/cpp/io/basic_istream/ignore

In your reply you referred to cin.ignore();. This will ignore 1 character or the (\n) whichever comes first. Extracting from the stream and then discarding it. Some people use cin.ignore(1000); leaving the 2nd parameter as the default (\n). As the link mentions cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n') would be the more portable way of using the ignore as any compiler can use it because not all header files for a compiler are the same and may define the maximum buffer size differently.

I do not know what compiler you are using, but I usually put this at the end of "main" return 0; // <--- Not required, but makes a good break point. .

History is never good for me, so I am not sure if this was always in the C++11 standards or a revision when the 2014 standards came out. Either way it is no longer required as it will return (0) zero if it is not there.

Andy
cin.ignore();. This will ignore 1 character or the (\n) whichever comes first. Extracting from the stream and then discarding it. Some people use cin.ignore(1000); leaving the 2nd parameter as the default (\n).

I'm sure I've told you this before, but the default isn't '\n'! It's Traits::eof(), so you need to specify the '\n' if that's what you want. (Of course "whichever comes first" is meaningless if it's just 1 character.)

History is never good for me

C++ was always that way, even before C++11.
Last edited on
@Handy Andy, @dutch,
Ah, I see. So if you entered only one char, it would ignore that?
>>, getline(), and ignore() all read some characters from the stream. They don't care what the user enters. If the code is to get 7 characters from the stream, then that function will continue until it has got 7 characters.

In other words: not "if entered only one" but "It will ignore next character"


agent max wrote:
this is not good programming practice, because 1: it dynamically allocates memory at run-time without requesting it, and 2: you can run into memory issues when you do that, particularly because you're using strings which also dynamically allocate memory. You're better off using a pointer to properly dynamically allocate the memory.

VLA (variable length array) is worse than "not good". It is invalid in C++. Undefined behaviour.
Some compilers have support for VLA in C++, but then code is not portable. Yes, that is "not good practice".

C++ Standard Library offers std::vector. That is the C++ way to have a "VLA". The vector is "a pointer" with syntactic sugar. Sweet.

Your code sample has raw pointer from new [], but you don't show delete []. Nobody is "better off" by learning only small part of memory management. The 'new' statement is trivial. The 'delete' can be deviously hard. Plenty of crashes or memory leaks (that ultimately lead to crashes) are due to inappropriate or lacking delete.
Manual memory management is not good programming practice.

The std::vector does not forget the deallocation. It knows the tricky cases.
Ah! Yes, thank you @keskiverto for pointing that out, I forgot to delete the allocated memory. I will edit it and add the necessary code.

And you are right, vectors are a better way to do it. However, there are probably situations where dynamically allocated arrays are better (I can't think of any right now).
Note that in this situation, you can remove the unwanted \n left by >> as per L17 in my code above.
@seeplus,
I haven't seen it done that way before, but dang, it works!

But why did you try to initialize arraySize like this?
1
2
// What's with the brackets?
size_t arraySize {};

It doesn't work–my compiler gave me an error when I tried to compile it.
Last edited on
That's default initialisation - it needs C++17 to compile. It initialises the variable to the default for the specified type - which for size_t is 0UL or 0ULL depending upon whether compiling for 32 or 64 bits.

Ah, ok. I don't think my compiler has C++17 standards. I think it only has up to C++ 11, but I'm not sure how to find out. Unless you know of some functions that are from the next version (C++14), that I could try compiling.
Brace-initialization is a C++11 feature. Intro: https://www.informit.com/articles/article.aspx?p=1852519


Which compiler (and version)?
@keskiverto,
I guess my compiler is older than I thought. I use the clang compiler in the Terminal application on my Mac. This is the version:
Apple LLVM version 10.0.0 (clang-1000.10.44.4)
Target: x86_64-apple-darwin17.7.0
Thread model: posix


I don't know if that's an old compiler or not, but it sometimes gives me warnings that "something-or-other is a C++11 extension." But it still compiles and runs fine.

max

Edit:
@seeplus,
So, in another topic, called HTML Table with C++, I had a similar problem, and a guy named @Ganado helped me with it. He suggested I set this flag: -std=c++11 when compiling to allow it to compile with C++11. So I tried that with your program, but I set a C++17 flag, and what do you know? It compiled and ran perfectly!
Link to the post: http://www.cplusplus.com/forum/general/276345/#msg1192480
So I guess my compiler does have the C++17 standards, they're just not the default!
Last edited on
I guess my compiler is older than I thought.

You've tried -std=c++17 and it compiled fine. Try -std=c++2a (C++20).

If that errors out your compiler isn't all that old. A bit behind the soon to be standard, but not as bad as it could be.
A bit behind the soon to be standard


C++20 is now the current standard.

This was technically finalized by WG21 at the meeting in Prague in February 2020, approved on 4th September 2020, and published by ISO in December 2020.
OK, thanks @Furry Guy, I'll try that out!

Edit:
Well I'll be danged! It worked! Ok, I'm going to start setting that flag when I compile programs!

Thanks a million!
max
Last edited on
Topic archived. No new replies allowed.