Existe uma razão técnica para usar> (<) em vez de! = Ao incrementar 1 em um loop 'for'?

198

Quase nunca vejo um forloop como este:

for (int i = 0; 5 != i; ++i)
{}

Existe um motivo técnico para usar >ou em <vez de !=incrementar 1 em um forloop? Ou isso é mais uma convenção?

Zingam
fonte
104
Torna-o mais legível, além disso, se você mudar i++para i+=2(por exemplo), ele será executado por um período muito longo (ou possivelmente para sempre). Agora, como você normalmente usa <para os casos em que você incrementa o iterador em mais de 1, você também pode usar <também para o caso em que você incrementa em 1 (por consistência).
barak manos
112
5 != ié mau
Slava
27
Você deve sempre estar consciente do que está fazendo, mas cometerá erros de qualquer maneira. Usar <reduz a possibilidade de alguém introduzir um bug nesse código.
Aurast
40
@OleTange Se você está interagindo com números de ponto flutuante você já está ferrado ..
CaptainCodeman
29
@ Slava ... não é mau. Aparentemente, você nunca foi mordido por um simples erro de digitação em C, fazendo a diferença entre if ( i == 5 ) ...e if ( i = 5 ). Coisas muito diferentes. A reversão dos operandos evita o problema: como os literais não são lvals, eles não podem ser atribuídos e o compilador lança o erro de digitação. @Zingam: boa programação defensiva!
Nicholas Carey

Respostas:

303
while (time != 6:30pm) {
    Work();
}

São 6:31 da tarde ... Droga, agora minha próxima chance de ir para casa é amanhã! :)

Isso mostra que a restrição mais forte atenua os riscos e é provavelmente mais intuitiva de entender.

Antonio
fonte
25
Às vezes, tentar "mitigar riscos" acaba escondendo o erro. Se o design do loop impedir que as 18:30 passem despercebidas, o uso <ocultará o erro, mas o uso !=tornaria óbvio que há um problema.
Adrian McCarthy
27
@AdrianMcCarthy: Não necessariamente; ele só poderia introduzir um segundo bug, tornando o diagnóstico mais difícil .
Lightness Races in Orbit
4
@AdrianMcCarthy: Esse é o meu ponto de vista; você pode ter alguns exemplos que ainda não viu;)
Lightness Races in Orbit
6
Os iteradores são um exemplo perfeito do ponto @AdrianMcCarthy, eu acho. A comparação recomendada para eles é! = Em vez de <.
Taekahn
5
Eu já vi exatamente esse erro (e causou 3 meses de depuração) - mas essa resposta erra totalmente o ponto. No exemplo dado, é impossível que a condição final seja perdida. Você pode até dizer que escolher conscientemente! = Over <é fazer uma forte afirmação desse fato. Mitigar um risco que definitivamente não existe é um cheiro de código para mim. (Dito isto, você pode igualmente argumentar que <é idiomático, que isso é uma boa razão para usá-lo como qualquer outro.)
Ian Goldby
95

Não há razão técnica. Mas há mitigação de riscos, capacidade de manutenção e melhor entendimento do código.

<ou >há restrições mais fortes do que !=e cumprem exatamente o mesmo objetivo na maioria dos casos (eu diria mesmo em todos os casos práticos).

Há uma pergunta duplicada aqui ; e uma resposta interessante .

Ely
fonte
6
Existem alguns tipos, como iteradores, que não suportam <ou>, mas suportam == e! =.
Simon B
1
É um loop for com int . Sem iteradores.
Ely
7
"Mas há mitigação de risco, capacidade de manutenção e melhor entendimento do código". Todos esses são, adequadamente, motivos técnicos. :-)
TJ Crowder
@TJCrowder Que tipo de razão ocorre quando você quer apenas falar sobre o que as máquinas farão como resultado?
Brilliand
1
@DanSheppard Eu geralmente consideraria a atenuação do risco e a manutenção como razões de negócios, e uma melhor compreensão do código como uma razão social (embora todas essas razões estejam sendo aplicadas a uma questão técnica neste caso). As considerações de "mitigação de risco" não se limitam de maneira alguma a questões técnicas, e as considerações de "melhor compreensão do código" podem mudar se você se encontrar trabalhando com um grupo diferente de pessoas (mesmo que as máquinas envolvidas não mudem nada )
Brilliand
85

Sim, há uma razão. Se você escrever um loop simples (baseado em índice antigo simples) como este

for (int i = a; i < b; ++i){}

então funciona como esperado para quaisquer valores de ae b(ou seja, zero iterações quando, em a > bvez de infinito, se você tivesse usado i == b;).

Por outro lado, para iteradores, você escreveria

for (auto it = begin; it != end; ++it) 

porque qualquer iterador deve implementar um operator!=, mas não para todo iterador, é possível fornecer um operator<.

Também baseado em intervalo para loops

for (auto e : v)

não são apenas açúcar sofisticado, mas reduzem mensurável as chances de escrever código errado.

idclev 463035818
fonte
4
Belo exemplo. Eu estaria interessado em um caso em !=vez de <. Eu pessoalmente nunca usei o que penso.
Ely
@Elyasin Eu não encontrei um bom, e não queria postar um ruim: imagine que você tenha algum tipo de contêiner circular, onde você incrementa em + x módulo o tamanho do contêiner N e deseja interromper o ciclo quando alcançar um certo índice .... bem, isso é um péssimo exemplo. Talvez eu vou encontrar um melhor
idclev 463035818
O mesmo loop com! = Em vez de <deixa claro qual é a vantagem de <(ou>) nesse contexto. for (int i=a; i != b; i++) {}
Paul Smith
10
Usar qualquer coisa além de !=iteradores é bastante perigoso, porque às vezes os iteradores podem ser menos que comparados (é um ponteiro, por exemplo), mas a comparação não tem sentido (é uma lista vinculada).
Zan Lynx
1
Aprenda a usar o espaço em branco, seriamente.
Rout de milhas
70

Você pode ter algo como

for(int i = 0; i<5; ++i){
    ...
    if(...) i++;
    ...
}

Se sua variável de loop for gravada pelo código interno, isso i!=5poderá não ocorrer . É mais seguro verificar se há desigualdade.

Edite sobre legibilidade. A forma de desigualdade é muito mais usada. Portanto, é muito rápido ler isso, pois não há nada de especial para entender (a carga cerebral é reduzida porque a tarefa é comum). Portanto, é legal que os leitores façam uso desses hábitos.

johan d
fonte
6
Esse tipo de "if (condição) então i ++" é a primeira coisa que pensei.
WernerCD
3
Veio esperando que esta fosse a resposta mais votada; Fiquei surpreso por ter que rolar até aqui para encontrá-lo. Isso faz muito mais para convencer um programador iniciante do que "bem, você deve usar a condição mais forte". As outras respostas, se permanecerem no topo, devem incorporar isso como uma explicação clara e óbvia do que pode dar errado no código proposto pelo OP.
msouth
1
@msouth concordo plenamente, mas meu POV é bastante subjetiva;)
d Johan
3
@msouth Adoro quando um comportamento inesperado da produção expõe meus erros, não é? :-)
deworde
3
@msouth Olha, tudo o que temos a fazer é nunca cometer erros e tudo ficará bem. Simples.
deworde
48

E por último, mas não menos importante, isso é chamado de programação defensiva , o que significa sempre levar o caso mais forte para evitar erros atuais e futuros que influenciam o programa.

O único caso em que a programação defensiva não é necessária é onde os estados foram comprovados pelas condições pré e pós (mas, provando que essa é a mais defensiva de toda a programação).

Paul Ogilvie
fonte
2
Um bom exemplo disso: a memória é vulnerável aos bits flips ( SEUs ) causados ​​pela radiação. Ao usar um intpara uma i != 15condição, o contador estará funcionando por um longo tempo se algo acima do quarto bit for invertido, especialmente em máquinas com sizeof(int)64. SEUS são uma preocupação muito real em grandes altitudes ou no espaço (devido à maior radiação) , ou em supercomputadores grandes (porque há muita memória).
21716 Josh Sanford
2
Pensar que seu programa funcionará bem quando a radiação estiver mudando sua memória é uma maneira otimista e anticatastrófica de pensar ... bom comentário! :)
Luis Colorado
37

Eu argumentaria que uma expressão como

for ( int i = 0 ; i < 100 ; ++i )
{
  ...
}

é mais expressivo de intenção do que é

for ( int i = 0 ; i != 100 ; ++i )
{
  ...
}

O primeiro afirma claramente que a condição é um teste para um limite superior exclusivo em um intervalo; o último é um teste binário de uma condição de saída. E se o corpo do loop não for trivial, pode não parecer aparente que o índice seja modificado apenas na forprópria declaração.

Nicholas Carey
fonte
13
"Quero que esse loop seja executado no máximo 5 vezes" vs. "Quero executar esse loop quantas vezes for necessário, exceto exatamente 5 vezes, o que não quero".
bispo
+1 por mencionar o limite superior de um intervalo. Eu acho que isso é importante para intervalos numéricos. ! = Não define um intervalo adequado em um loop como estes
element11
22

Os iteradores são um caso importante quando você costuma usar a !=notação:

for(auto it = vector.begin(); it != vector.end(); ++it) {
 // do stuff
}

Concedido: na prática, eu escreveria o mesmo contando com range-for:

for(auto & item : vector) {
 // do stuff
}

mas o ponto permanece: normalmente se compara os iteradores usando ==or !=.

Escualo
fonte
2
Os iteradores geralmente têm apenas uma noção de igualdade / desigualdade e não uma ordem, é por isso que você os usa !=. Por exemplo, em um std::vectorvocê poderia usar <como o iterador está vinculado ao índice / ponteiro, mas em um std::setnão existe uma ordem estrita, pois ele caminha em uma árvore binária.
Martin C.
19

A condição do loop é um loop forçado invariável.

Suponha que você não olhe para o corpo do loop:

for (int i = 0; i != 5; ++i)
{
  // ?
}

nesse caso, você sabe no início da iteração do loop que inão é igual 5.

for (int i = 0; i < 5; ++i)
{
  // ?
}

nesse caso, você sabe que no início da iteração do loop ié menor que 5.

O segundo é muito, muito mais informação que o primeiro, não? Agora, a intenção do programador é (quase certamente) a mesma, mas se você estiver procurando por erros, ter confiança na leitura de uma linha de código é uma coisa boa. E a segunda aplica essa invariante, o que significa que alguns bugs que o afetariam no primeiro caso simplesmente não podem acontecer (ou não causam corrupção de memória, por exemplo) no segundo caso.

Você sabe mais sobre o estado do programa, lendo menos código, com o <que com !=. E nas CPUs modernas, elas levam a mesma quantidade de tempo que nenhuma diferença.

Se você inão foi manipulado no corpo do loop, e sempre foi aumentado em 1, e começou menos que 5, não haveria diferença. Mas, para saber se foi manipulado, você teria que confirmar cada um desses fatos.

Alguns desses fatos são relativamente fáceis, mas você pode errar. Verificar todo o corpo do loop é, no entanto, uma dor.

Em C ++, você pode escrever um indexestipo que:

for( const int i : indexes(0, 5) )
{
  // ?
}

faz a mesma coisa que qualquer um dos dois forloops acima , mesmo no compilador, otimizando-o para o mesmo código. Aqui, no entanto, você sabe que inão pode ser manipulado no corpo do loop, como é declarado const, sem que o código corrompa a memória.

Quanto mais informações você puder obter de uma linha de código sem precisar entender o contexto, mais fácil será rastrear o que está errado. <no caso de loops inteiros, você obtém mais informações sobre o estado do código nessa linha do que !=faz.

Yakk - Adam Nevraumont
fonte
13

Sim; O OpenMP não paralela os loops com a !=condição.

user541686
fonte
13

Pode acontecer que a variável iesteja configurada com algum valor grande e, se você apenas usar o !=operador, você terminará em um loop infinito.

LSchueler
fonte
1
Não é realmente interminável - na maioria das implementações de C, isilenciosamente, quando estiver no máximo. Mas sim, provavelmente mais do que você está preparado para esperar.
usr2564301
12

Como você pode ver nas outras inúmeras respostas, existem razões para usar <em vez de! =, O que ajudará em casos extremos, condições iniciais, modificação não desejada do contador de loop, etc ...

Honestamente, porém, não acho que você possa enfatizar a importância da convenção o suficiente. Neste exemplo, será fácil o suficiente para outros programadores verem o que você está tentando fazer, mas isso causará uma dupla análise. Um dos trabalhos durante a programação é torná-lo o mais legível e familiar possível para todos, tão inevitavelmente quando alguém precisa atualizar / alterar seu código, que não é preciso muito esforço para descobrir o que você estava fazendo em diferentes blocos de código. . Se eu visse alguém usar !=, eu assumiria que havia uma razão para eles o usarem , <e se fosse um loop grande, eu examinaria a coisa toda tentando descobrir o que você fez que tornou isso necessário ... e isso é perda de tempo.

RyanP
fonte
12

Como já foi dito por Ian Newson, você não pode fazer um loop confiável sobre uma variável flutuante e sair com !=. Por exemplo,

for (double x=0; x!=1; x+=0.1) {}

na verdade fará um loop para sempre, porque 0,1 não pode exatamente ser representado em ponto flutuante, portanto, o contador erra um pouco 1. Com <ele termina.

(Observe, no entanto, que é basicamente um comportamento indefinido se você obtém 0,9999 ... como o último número aceito - o que meio que viola a suposição menor que - ou já sai em 1.0000000000000001.)

leftaroundabout
fonte
10

Entendo o adjetivo "técnico" como comportamento / peculiaridades da linguagem e efeitos colaterais do compilador, como desempenho do código gerado.

Para esse fim, a resposta é: não (*). O (*) é "por favor consulte o manual do processador". Se você estiver trabalhando com algum sistema RISC ou FPGA de ponta, talvez seja necessário verificar quais instruções são geradas e quanto custam. Mas se você estiver usando praticamente qualquer arquitetura moderna convencional, não haverá diferença significativa no nível do processador no custo entre lt,eq , nee gt.

Se você estiver usando um caso de borda, poderá descobrir que !=requer três operações ( cmp,not , beq) contra dois ( cmp, blt xtr myo). Mais uma vez, a RTM nesse caso.

Na maioria das vezes, os motivos são defensivos / endurecedores, especialmente ao trabalhar com ponteiros ou loops complexos. Considerar

// highly contrived example
size_t count_chars(char c, const char* str, size_t len) {
    size_t count = 0;
    bool quoted = false;
    const char* p = str;
    while (p != str + len) {
        if (*p == '"') {
            quote = !quote;
            ++p;
        }
        if (*(p++) == c && !quoted)
            ++count;
    }
    return count;
}

Um exemplo menos artificial seria onde você está usando valores de retorno para realizar incrementos, aceitando dados de um usuário:

#include <iostream>
int main() {
    size_t len = 5, step;
    for (size_t i = 0; i != len; ) {
        std::cout << "i = " << i << ", step? " << std::flush;

        std::cin >> step;
        i += step; // here for emphasis, it could go in the for(;;)
    }
}

Tente isso e insira os valores 1, 2, 10, 999.

Você pode impedir isso:

#include <iostream>
int main() {
    size_t len = 5, step;
    for (size_t i = 0; i != len; ) {
        std::cout << "i = " << i << ", step? " << std::flush;
        std::cin >> step;
        if (step + i > len)
            std::cout << "too much.\n";
        else
            i += step;
    }
}

Mas o que você provavelmente queria era

#include <iostream>
int main() {
    size_t len = 5, step;
    for (size_t i = 0; i < len; ) {
        std::cout << "i = " << i << ", step? " << std::flush;
        std::cin >> step;
        i += step;
    }
}

Há também um viés de convenção <, porque a ordem em contêineres padrão geralmente depende operator<, por exemplo, o hash em vários contêineres STL determina a igualdade dizendo

if (lhs < rhs) // T.operator <
    lessthan
else if (rhs < lhs) // T.operator < again
    greaterthan
else
    equal

Se lhse rhsé uma classe definida pelo usuário, escrevendo este código como

if (lhs < rhs) // requires T.operator<
    lessthan
else if (lhs > rhs) // requires T.operator>
    greaterthan
else
    equal

O implementador deve fornecer duas funções de comparação. Então, <tornou-se o operador preferido.

kfsone
fonte
Para facilitar a leitura, i + = etapa deve estar na parte de controle. No se você pisaria = 0
Mikkel Christiansen
1
Enquanto que ajudaria a legibilidade do código bom, eu queria enfatizar a falha na versão errada
kfsone
9

Existem várias maneiras de escrever qualquer tipo de código (geralmente); neste caso, existem duas maneiras (três se você contar <= e> =).

Nesse caso, as pessoas preferem> e <para garantir que, mesmo que algo inesperado aconteça no loop (como um bug), ele não funcionará infinitamente (BAD). Considere o seguinte código, por exemplo.

for (int i = 1; i != 3; i++) {
    //More Code
    i = 5; //OOPS! MISTAKE!
    //More Code
}

Se usássemos (i <3), estaríamos a salvo de um loop infinito, porque isso colocava uma restrição maior.

É realmente sua escolha se você quer um erro no seu programa para desligar tudo ou continuar funcionando com o bug.

Espero que isso tenha ajudado!

Programador aleatório 123
fonte
um poderia argumento de que o loop infinito seria um bom indicador do erro, mas depois outro diria que i = 5 não é necessariamente um erro
njzk2
7

O motivo mais comum de usar <é a convenção. Mais programadores pensam em loops como "enquanto o índice está dentro do intervalo" e não "até que o índice chegue ao fim". Há um valor que adere à convenção quando você pode.

Por outro lado, muitas respostas aqui alegam que o uso do <formulário ajuda a evitar erros. Eu diria que, em muitos casos, isso apenas ajuda a ocultar bugs. Se o índice do loop deve atingir o valor final e, em vez disso, realmente ultrapassar, então algo acontecendo que você não esperava que pode causar um mau funcionamento (ou ser um efeito colateral de outro bug). O <provável vai atrasar descoberta do bug. O !=é mais susceptível de conduzir a uma tenda, cair, ou mesmo um acidente, o que irá ajudar a detectar o erro mais cedo. Quanto mais cedo um bug for encontrado, mais barato será o reparo.

Observe que essa convenção é peculiar à indexação de vetores e matrizes. Ao percorrer quase qualquer outro tipo de estrutura de dados, você usaria um iterador (ou ponteiro) e verificaria diretamente um valor final. Nesses casos, você deve ter certeza de que o iterador alcançará e não excederá o valor final real.

Por exemplo, se você estiver percorrendo uma string C simples, geralmente é mais comum escrever:

for (char *p = foo; *p != '\0'; ++p) {
  // do something with *p
}

do que

int length = strlen(foo);
for (int i = 0; i < length; ++i) {
  // do something with foo[i]
}

Por um lado, se a string for muito longa, a segunda forma será mais lenta porque strlenhá outra passagem pela string.

Com um C ++ std :: string, você usaria um loop for baseado em intervalo, um algoritmo padrão ou iteradores, mesmo que o comprimento esteja prontamente disponível. Se você estiver usando iteradores, a convenção é usar em !=vez de <, como em:

for (auto it = foo.begin(); it != foo.end(); ++it) { ... }

Da mesma forma, a iteração de uma árvore ou de uma lista ou deque geralmente envolve vigiar um ponteiro nulo ou outro sentinela, em vez de verificar se um índice permanece dentro de um intervalo.

Adrian McCarthy
fonte
3
Você está certo ao enfatizar a importância do idioma na programação. Se eu olhar para algum código e ele tiver um padrão familiar, não preciso perder tempo deduzindo o padrão, mas posso ir direto ao âmago dele. Eu acho que essa é a minha principal preocupação com as comparações Yoda - elas não parecem idiomáticas, então eu acabei tendo que lê-las duas vezes para ter certeza de que elas querem dizer o que eu acho que elas querem dizer.
precisa
7

Um motivo para não usar essa construção é o número de ponto flutuante. !=é uma comparação muito perigosa para usar com carros alegóricos, pois raramente será avaliada como verdadeira, mesmo que os números tenham a mesma aparência. <ou >remove esse risco.

Ian Newson
fonte
Se o seu iterador de loop for um número de ponto flutuante, o !=versus <é o menor dos seus problemas.
Lundin
7

Há duas razões relacionadas para seguir essa prática que ambas têm a ver com o fato de que uma linguagem de programação é, afinal, uma linguagem que será lida por seres humanos (entre outros).

(1) Um pouco de redundância. Em linguagem natural, geralmente fornecemos mais informações do que o estritamente necessário, como um código de correção de erros. Aqui a informação extra é que a variável loop i(veja como usei a redundância aqui? Se você não sabia o que significa 'variável loop', ou se esqueceu o nome da variável, depois de ler "variável variável i", você tem a opção completa informações) é menor que 5 durante o loop, não apenas diferente de 5. A redundância aprimora a legibilidade.

(2) Convenção. Os idiomas têm maneiras padrão específicas de expressar determinadas situações. Se você não seguir a maneira estabelecida de dizer algo, ainda será compreendido, mas o esforço para o destinatário da sua mensagem é maior porque certas otimizações não funcionam. Exemplo:

Não fale sobre a mistura quente. Apenas ilumine a dificuldade!

A primeira frase é uma tradução literal de um idioma alemão. O segundo é um idioma inglês comum, com as palavras principais substituídas por sinônimos. O resultado é compreensível, mas leva muito mais tempo para entender do que isso:

Não rodeios. Apenas explique o problema!

Isso é verdade mesmo que os sinônimos usados ​​na primeira versão se ajustem melhor à situação do que as palavras convencionais no idioma inglês. Forças semelhantes estão em vigor quando os programadores leem o código. É também por isso 5 != ie 5 > isão maneiras estranhas de colocá-lo, a menos que você esteja trabalhando em um ambiente no qual é padrão trocar o mais normal i != 5e i < 5dessa maneira. Tais comunidades de dialetos existem, provavelmente porque a consistência facilita lembrar de escrever em 5 == ivez do natural, mas propenso a erros i == 5.


fonte
1
Ausgezeichnet . Da mesma forma, não se escreveria o teste como i < 17+(36/-3)(mesmo quando são constantes usadas em outros lugares; você deve escrever os nomes deles para maior clareza!).
usr2564301
6

Usar comparações relacionais nesses casos é um hábito mais popular do que qualquer outra coisa. Ele ganhou popularidade nos tempos em que considerações conceituais como categorias de iteradores e sua comparabilidade não eram consideradas de alta prioridade.

Eu diria que é preferível usar comparações de igualdade em vez de comparações relacionais sempre que possível, uma vez que as comparações de igualdade impõem menos requisitos aos valores que estão sendo comparados. Ser um EqualityComparable é um requisito menor do que ser LessThanComparable .

Outro exemplo que demonstra a aplicabilidade mais ampla da comparação de igualdade em tais contextos é o enigma popular com a implementação da unsignediteração até 0. Isso pode ser feito como

for (unsigned i = 42; i != -1; --i)
  ...

Observe que o acima descrito é igualmente aplicável à iteração assinada e não assinada, enquanto a versão relacional é dividida em tipos não assinados.

Formiga
fonte
2

Além dos exemplos, onde a variável de loop muda (não intencionalmente) dentro do corpo, existem outras maneiras de usar os operadores menores ou maiores que:

  • Negações tornam o código mais difícil de entender
  • <ou >é apenas um caractere, mas !=dois
MiCo
fonte
4
A segunda bala é, na melhor das hipóteses, uma razão frívola. O código deve estar correto e claro. Compactar é muito menos importante.
27616 Jonathan Leffler
@JonathanLeffler Bem, em um TDD REPL, esse caractere extra é um nanossegundo extra para análise e vezes um bilhão de iterações para encontrar o bug causado pela escrita 5 != $i, que levou apenas um segundo da minha vida. Uh ... snicker
bispo
1

Além das várias pessoas que mencionaram que isso atenua o risco, também reduz o número de sobrecargas de função necessárias para interagir com vários componentes da biblioteca padrão. Por exemplo, se você deseja que seu tipo seja armazenável em um std::set, ou usado como chave para std::map, ou usado com alguns dos algoritmos de busca e classificação, a biblioteca padrão geralmente usa std::lesspara comparar objetos, pois a maioria dos algoritmos precisa apenas de uma ordem fraca estrita . Assim, torna-se um bom hábito usar as <comparações em vez de !=comparações (onde faz sentido, é claro).

Andre Kostur
fonte
1
você pode estar certo quanto ao número de sobrecargas, mas ao considerar os requisitos dos objetos, para quase qualquer objeto é possível definir um !=operador, mas nem sempre é possível definir uma ordem estritamente fraca. Nesse sentido, !=seria melhor, porque coloca menos requisitos no tipo. No entanto, eu ainda fico com o <.
Idclev 463035818
0

Não há problema do ponto de vista da sintaxe, mas a lógica por trás dessa expressão 5!=inão é sólida.

Na minha opinião, usar !=para definir os limites de um loop for não é logicamente válido, porque um loop for aumenta ou diminui o índice de iteração, portanto, definir o loop para iterar até que o índice de iteração fique fora dos limites ( !=para algo) não é um implementação adequada.

Ele vai trabalhar, mas é propenso ao mau comportamento desde a manipulação de dados limite é perdida quando se utiliza !=para um problema incremental (o que significa que você sabe desde o início se ele aumenta ou diminui), por isso, em vez !=do <>>==>são utilizados.

Cosmin Gherghel
fonte
2
A lógica está perfeitamente bem. Quando ié 5o loop termina. Você quis dizer mais alguma coisa?
18555 Dan Getz
1
Se os dados não forem transferidos corretamente devido ao calor, as influências eletromagnéticas do seu código serão executadas para sempre. Se você fizer isso em uma estação de trabalho regular ou servidor com ECC RAM não é problema (nem lógica, técnica nem física)
Markus