1

The first loop is works perfect. Second doesn't works. What is wrong with 'Z'. Why the loop doesn't stop? When I will give 'Z' inside in table the loop doesn't react.

#include <iostream>
using namespace std;

int main()
{
    char tab[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G',
                'H', 'I', 'J', 'K', 'L', 'M', 'N',
                'O', 'P', 'Q', 'R', 'S', 'T', 'U',
                'V', 'W', 'X', 'Y', 'Z' };

    char *wsk = tab;

    while(*wsk <= 'Y')
    {
        cout << *wsk << " ";
        wsk++;
    }
    cout << endl;

    wsk = tab;
    while(*wsk <= 'Z')
    {
        cout << *wsk << " ";
        wsk++;
    }
    cout << endl;
}

2
  • Usually you'd add a 0 to the end of the list as a terminator, not an arbitrary 'Z'. Also as this is C++ you can use std::vector or std::array and regular iterators, there's no need for C-style arrays. Commented Aug 1, 2019 at 16:55
  • I didn't mean solution but awareness that I'm leaving out of range the tab Commented Aug 1, 2019 at 17:58

5 Answers 5

6

'Z' is the last element of the array. At the end of (what is supposed to be) the last iteration, wsk is incremented to point beyond the last element of the array. In the next iteration, *wsk <= 'Z' indirects through the pointer that is out of bounds, attempts to access an object that doesn't exist, and behaviour of the program is undefined.

A simple solution to loop over an entire array:

for(char c : tab)

A solution using a pointer:

char* end = std::end(tab);
for(char* wsk = tab; wsk != end; wsk++)

You can break the loop early based on condition:

for(char c : tab) {
    std::cout << c;
    if (c >= 'Z')
        break;
}

If you specifically want a loop, that ends when a certain value is encountered, but that element must also be iterated, and know for certain that the value is guaranteed to exist, and for some reason cannot know the length of the array, then you could possibly use:

wsk = tab;
do {
    char c = *wsk++;
    std::cout << c;
} while(c < 'Z');

But note that this will also have UB if that element does not exist in the array.

Sign up to request clarification or add additional context in comments.

3 Comments

wsk != end ==> wsk != end && *wsk <= 'Z'
@WhozCraig possibly; depending on what is OP's intention.
Agreed. The intention is clear in the original while conditions afaic.
1

This is Undefined Behavior.

while(*wsk <= 'Z')

You probably want to loop until you find Z, print the Z and then exit the loop, right? But that's not what's happening here. You hit the Z, but *wsk <= 'Z' is still true, so you'll keep looping.

When you do wsk++;, you're now out of the range of your array! And what is in this big wide world of open memory you just stepped into? Who knows!!

Given what you want to do here, you could fix this by adding a terminating character to your array that is the largest char value:

char tab[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G',
            'H', 'I', 'J', 'K', 'L', 'M', 'N',
            'O', 'P', 'Q', 'R', 'S', 'T', 'U',
            'V', 'W', 'X', 'Y', 'Z', 0x7f };
//                                  ^^^^^^
//Add the largest char to the end of the array

Note that this will also prevent your first loop from causing undefined behavior in the case that you have an array with characters that are all <= 'Y'. We're essentially guaranteeing here that you won't go out of bounds no matter the contents.

Comments

0

Use vector and range for loop:

#include <iostream>
#include<vector>
using namespace std;

int main()
{
    vector<char> tab = { 'A', 'B', 'C', 'D', 'E', 'F', 'G',
                'H', 'I', 'J', 'K', 'L', 'M', 'N',
                'O', 'P', 'Q', 'R', 'S', 'T', 'U',
                'V', 'W', 'X', 'Y', 'Z', 0};


    for(auto it:tab){
        cout<<it<<" ";
        if(it>'Z')
            break;
        }
    cout << endl;
}

Live

Comments

0

The problem as usual is you are selected a wrong loop.:)

So within the loop you are continuing iteration beyond the array.

This condition

*wsk <= 'Z'

does not prevent the loop to make one more iteration and by means of increasing the pointer

wsk++;

to access memory after the last element of the array.

Use instead the do-while loop.

Here is a demonstrative program

#include <iostream>

int main() 
{
    char tab[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G',
                'H', 'I', 'J', 'K', 'L', 'M', 'N',
                'O', 'P', 'Q', 'R', 'S', 'T', 'U',
                'V', 'W', 'X', 'Y', 'Z' };

    for ( char c : tab )
    {
        const char *wsk = tab;

        do
        {
            std::cout << *wsk << " ";
        } while ( *wsk++ != c );

        std::cout << '\n';
    }       

    return 0;
}

Its output is

A 
A B 
A B C 
A B C D 
A B C D E 
A B C D E F 
A B C D E F G 
A B C D E F G H 
A B C D E F G H I 
A B C D E F G H I J 
A B C D E F G H I J K 
A B C D E F G H I J K L 
A B C D E F G H I J K L M 
A B C D E F G H I J K L M N 
A B C D E F G H I J K L M N O 
A B C D E F G H I J K L M N O P 
A B C D E F G H I J K L M N O P Q 
A B C D E F G H I J K L M N O P Q R 
A B C D E F G H I J K L M N O P Q R S 
A B C D E F G H I J K L M N O P Q R S T 
A B C D E F G H I J K L M N O P Q R S T U 
A B C D E F G H I J K L M N O P Q R S T U V 
A B C D E F G H I J K L M N O P Q R S T U V W 
A B C D E F G H I J K L M N O P Q R S T U V W X 
A B C D E F G H I J K L M N O P Q R S T U V W X Y 
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 

2 Comments

...isn't your do-while the same exact thing as while( *wsk++ != c ) { ...? I don't think there's really a need for do-while over while here at all. Your only difference is that you're incrementing before printing instead of after.
@scohe001 No, they are different. The do-while loop outputs all characters including c. Your loop skips the first character in the sequence because in the condition while( *wsk++ != c ) the pointer was incremented.
-1

After outputting 'Z', you increment wsk so that it points past the end of the array. Then it gets to while (*wsk <= 'Z'), where anything could happen because *wsk is referencing undefined memory.

You need while (*wsk < 'Z'), or perhaps

for ( ; ; )
  {
  cout << *wsk << " " ;
  if (*wsk >= 'Z') break ;
  wsk++ ;
  }

if you want to output the 'Z' before you exit the loop.

6 Comments

Then for( wsk = tab; true; ++wsk ) is better
@Slava or even for( wsk = tab; ; ++wsk)
@scohe001 thats matter of taste, I find it more readable to put true there explicitly.
@Slava: if it's a matter of taste, why did you feel you had to "correct" my code?
@TonyK matter of taste is to put true into condition part of for or leave it empty, as makes the same result. In your code you leave initialization part and increment part empty and then have 2 additional lines in the code that do it, which seems to be quite odd. For example code int i = 0; for( ; ; ) { if( i > 10 ) break; a[i] = 0; i++; } looks ugly and raises question why parts of for that are specially designed for it is not in use?.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.