Ir ao conteúdo

Posts recomendados

Postado

Sou iniciante em C++ e gostaria de simplificar os laços... li no meu livro de C++ que os parâmetros podem ser omitidos, mas ainda não acertei corretamente como fazer.

por exemplo este laço:

  for(pos = 0; pos < 16; pos++)
      {
        //função a ser executada               
      }

gostaria que ficasse como no pascal:

FOR CONT:=1 to 10 do

begin

end;

 

ou seja queria suprimir o parâmetro de incremento... (acho que se suprimir ele entenderia que o passo do incremento seria 1).

e no caso do pos <16 teria como colocar somente 16 (e o loop já saber que deve ir até 16 somente? sem ter que colocar uma verificação lógica?

 

e quanto ao caso da variável (que está sendo inicializada dentro do loop) teria como inicializar antes?

por exemplo:

pos = 5;    


for(pos; pos < 16; pos++)
      {
      //função a ser executada                   
      } 

neste caso o loop já iniciaria em 5 (mas eu poderia controlar externamente com que valor o loop iria iniciar...

 

Obrigado por todas as dicas.

  • Curtir 1
Postado

Ate tem como você fazer um for estilo Python e Pascal mas é algo um tanto complexo porque envolve templates, sobrecarga de operadores etc etc. O C++ a partir da versão 11 ate tem um for que é baseado em ranges mas ele precisa iterar a partir de alguma coisa, array ou vector.

std::string str = "clubedohardware"; 
    for (char c : str)  
        std::cout << c << ' '; 

 

Olha esse código retirado do stackoverflow com o for estilo Python.

#include <iostream>

template <typename T>
class Range {
public:
    class iterator {
    public:
        explicit iterator(T val, T stop, T step) : m_val(val), m_stop(stop), m_step(step) { }
        iterator& operator ++ ()
        {
            m_val += m_step;
            if ((m_step > 0 && m_val >= m_stop) ||
                    (m_step < 0 && m_val <= m_stop)) {
                m_val = m_stop;
            }
            return *this;
        }
        iterator operator ++ (int)
        {
            iterator retval = *this;
            ++(*this);
            return retval;
        }
        bool operator == (iterator other) const
        {
            return m_val == other.m_val;
        }
        bool operator != (iterator other) const
        {
            return !(*this == other);
        }
        T operator * () const
        {
            return m_val;
        }
    private:
        T m_val, m_stop, m_step;
    };

    explicit Range(T stop)
        : m_start(0), m_stop(stop), m_step(1)
    { }

    explicit Range(T start, T stop, T step = 1)
        : m_start(start), m_stop(stop), m_step(step)
    { }

    iterator begin() const
    {
        return iterator(m_start, m_stop, m_step);
    }
    iterator end() const
    {
        return iterator(m_stop, m_stop, m_step);
    }

private:
    T m_start, m_stop, m_step;
};

template <typename T>
Range<T> range(T stop)
{
    return Range<T>(stop);
}

template <typename T>
Range<T> range(T start, T stop, T step = 1)
{
    return Range<T>(start, stop, step);
}

int main()
{
    for (auto i : range(10)) {
        std::cout << " " << i;
    }
    std::cout << std::endl;
    for (auto i : range(4, 10, 2)) {
        std::cout << " " << i;
    }
    std::cout << std::endl;
    for (auto i : range(0.5, 1.0, 0.1)) {
        std::cout << " " << i;
    }
    std::cout << std::endl;
}

 

  • Curtir 1
  • Obrigado 1
Postado

Muito obrigado pelas dicas amigos...

estou conseguindo acertar agora...

este aqui funcionou muito bem para os propósitos que tenho:

  d=1;
  for(; d<=10; d++)
    printf("\n:%2i",d);

Com este já diminuiu um parâmetro e posso inicializar o loop com o valor que quiser (setando previamente a variável)

  • Curtir 1
Postado
Em 11/12/2019 às 13:46, KXSY disse:

Na realidade em pascal você também não está suprimindo o incremento, quando você passa a variável CONT para o for. ele entende que aquela variável será incrementada de um em um (ou o contrario com DOWNTO)

 

Sim. Não é você quem está suprimindo o incremento. Quem suprimiu o incremento foi o professor Wirth, criador da linguagem. Era uma das coisas que segundo ele levavam a escrever programas "menos legíveis" e "menos eficientes" como ele escreveu em Pascal User Manual and Report" o "livro do Pascal". Muito embora tenha derivado Pascal diretamente de Algol que tinha o parâmetro Step no loop, foi uma das muitas coisas que ele tirou.

 

for in C


O comando em C tem essas 3 partes e todas 3 são sim opcionais. É bem diferente do for em Pascal e é diferente por definição e limitado por decisão. Vou tentar explicar melhor com uns exemplos e referências.


As linguagens modernas tem em geral 3 variedades de loop.  Citando o Pascal: while/do, repeat/until e o for aritmético. C++ e java e outras tem um outro tipo de for, chamado range-based for loop e depois posso deixar um exemplo desses. Um loop é só tem um bloco anônimo de comandos e o comando define uma disciplina de repetição para ele. 

 

Bloco


Um bloco em Pascal tem lá Begin e End como delimitadores. C usa as chaves, como outras linguagens. FORTRAN usava o número de comando, e assim vai. Mas Pascal é mais restritivo em relação a isso.


Deixando o bloco no meio da execução


Pascal e C e outros implementam em geral um comando break e um comando continue que podem deixar em definitivo o loop ou passar de imediato para a próxima iteração, de modo que é comum usar loops ditos *infinitos* usando um comando desses durante a lógica interna ao loop. E em geral há um comando goto para desviar de fato a execução para outro ponto. E comandos como return e exit que tem efeito similar


for em Pascal


Pascal deriva diretamente e claramente da Linguagem Algol e o loop em Algol tinha um parâmetro STEP, como tem em outras linguagens como Visual Basic hoje. Por decisão do prof. Wirth , o criador de Pascal, *step* foi eliminado. E muitos odiaram.


Numa tradução direta do próprio "Pascal User Manual And Report" do criador da linguagem, o equivalente ao "livro branco"do C de Kernighan e Ritchie, você lê:

Citação

Num primeiro contato com Pascal muitos reclamam da ausência de certas "características favoritas" ... Essas omissões não são falhas mas sim omissões deliberadas. Em alguns casos a presença dessas coisas seria primariamente um convite à programação ineficiente; em em outras se sentiu que seria contrária ao sentido de clareza, de confiabilidade e "bom estilo de programação"

 

E ele de fato usou essas aspas nesse "bom estilo de programação"

 

Acho que ele era mesmo um pouco chato. E estava desenvolvendo o conceito do que ele chamava de programação estruturada que muitos dizem que evoluiu para a programação orientada a objetos de hoje --- que muitos escrevem OOP

 

De volta aos loops em C e Pascal


Um loop em Pascal é pobre e simplificado de propósito. Como não dá pra simplificar a lógica e a realidade, muitas vezes se vai odiar por exemplo a ausência do tal step no  for . Um dos objetivos de Pascal era ser _A_ linguagem para ensinar programação. E haviam muitas linguagens na época. Algol nunca ficou popular exceto em certos nichos, como universisdades que usavam computadores da Control Data. FORTRAN e COBOL eram as linguagens de largo uso. Programas em COBOL eram e são as coisas mais legíveis nessa área segundo muitos, mas raramente os autores sabiam ou sabem algo sobre COBOL então era e é um animal a parte. E FORTRAN era a vítima dos acadêmicos e seria substituído pelo moderno e estruturado Pascal em muitas universidades nos cursos inicias de programação.

 

Se você quer suprimir o parâmetro de incremento então está no caminho do Pascal mesmo. Mas em geral acho que não se pode omitir o begin / end de modo que se a ideia é simplificar não vai ser com Pascal, que sempre foi tida como uma linguagem "de muitas palavras". O parâmetro *step* não existe, mas o resto é bem engessado. E de propósito como explicado pelo autor. Autor da linguagem.

 

E qual o propósito de C


C derivou diretamente de uma linguagem chamada B e foi criada por cientistas em busca de uma linguagem para acelerar o desenvolvimento de sistemas. Do sistema Unix na Bell Labs em particular. E não por um professor com uma metodologia em mente.


Assim os comandos tem um sentido prático sempre. No caso do for:

for ( inicializacao; teste; incremento ) {bloco};

tem esse formato genérico, mas tudo é opcional

 

  • se o bloco tiver um só comando pode omitir `{}`
  • os 3 blocos são separados por duas `;` e essas e os parenteses são mandatórios
  • o primeiro bloco tem os comandos de inicialização, e pode ser como no Pascal
 for( int CONT=1;;){} 

por exemplo. Mas você pode declarar várias variáveis, escrever expressões separadas por `,` e tal. Bem flexível. Ou deixar em branco e o sistema não faz nada.

  •  o segundo bloco é qualquer coisa que se avalie para um resultado, com 1 sendo verdadeiro e 0 sendo falso. Uma expressão. Como algo assim
    for ( 
        int i = 0, j = 1;
        j = (i == 1) ? funcaoA(i,j): funcaoB(j);
        );  // sem a terceira parte


Que declara duas variáveis e termina apenas se j for zero, mas redefine j chamando funcaoA() ou funcaoB() conforme o valor de i. Esse é um exemplo besta só para mostrar o objetivo da linguagem: não ficar no seu caminho e tentar te dizer que assim vai melhor para você, como é em Pascal.

  • o incremento pode ser qualquer coisa, ou nada, nos mesmos moldes. Por exemplo, se você quiser incrementar uma variável que nada tem a ver com o loop e apenas sob certas condições e for algo que sempre é feito ao final do bloco, pode ficar mais claro colocar isso no próprio `for` para orientar o cara que for ler seu programa depois.

Veja um exemplo

    for (
        int i = 0, j = 1;
        j<4;
        j = (i == 1) ? j : j + 1
        )
    {
        printf("j = %d\n", j);
        i = (i + 1) % 2;
    }; // incrementa j sob certas condicoes apenas


Isso imprime 1 1 2 2 3 3 porque o valor de i vai alternando entre 0 e 1 e o `for` só incrementa `j` se `i` for 1.

  • E você pode omitir qualquer parte dessas ou todas. Em particular, se usar somente a segunda parte o comando é o próprio while 
while(condicao) printf("verdade\n");

e

for( ;condicao; ) printf("verdade\n");

são a mesma coisa

 

O outro loop: "range-based"


Em C++ ou java por exemplo


 

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

int main()
{
    std::vector<string> coisas = { "verde", "azul", "amarelo" };

    for (auto umaString : coisas)
    {
        cout << "uma coisa: " << umaString << endl;
    }   // for
    return 0;
};  // main()

mostra

uma coisa: verde
uma coisa: azul
uma coisa: amarelo

E isso funciona também em classes definidas pelo usuário, o que abriu um universo de possibilidades de escrever coisas bem legíveis com dados nem tão legíveis, como classes complexas...


Isso funciona porque a declaração auto faz com que o compilador procure o que pode ser a variável umaString a partir do que está depois dos ':' . Lá está coisas que foi declarado como vetor e o compilador verifica que é uma classe iterável. E é então o compilador define umaString como um iterador para std::vector e tudo funciona. 

 

Também para as classes que você escreve desde que você as torne iteráveis, o que é simples.

 

 

 

 

 

 

 

 

  • Curtir 1
  • Obrigado 1
Postado
2 horas atrás, Venus Guy disse:

 

Vou ver lá. Entendeu o que expliquei os loops? Tinha uma parte fora de ordem e mudei a redação. Estou perdendo a paciência com esse editor do forum. Demora demais para escrever qualquer coisa...

Postado
Em 11/12/2019 às 11:23, Blumer Celta disse:

for(pos = 0; pos < 16; pos++)      

{

    //função a ser executada

}

 

opa,

Em primeiro lugar faltou definir a varável pos. Neste caso é possível colocar na mesma expressão de inicialização :

for (int pos=0; pos < 16; pos++) {comandos a serem executados todos separados por vírgula). Note que essa construção não é recomendada por questão de clareza.

 

Abraço,

 

Ps: o pos++ poderia ser eliminado caso em uma das operações do loop já o incrementasse.

 

  • Curtir 1
Postado
4 horas atrás, sodcpp disse:

Em primeiro lugar faltou definir a varável pos. Neste caso é possível colocar na mesma expressão de inicialização :

for (int pos=0; pos < 16; pos++) {comandos a serem executados todos separados por vírgula). Note que essa construção não é recomendada por questão de clareza.

 

Abraço,

 

Ps: o pos++ poderia ser eliminado caso em uma das operações do loop já o incrementasse

 

Cuidado: não é bem assim. 

 

@sodcpp talvez deva ver os exemplos no post #9 logo acima onde tem uns exemplos do que significa excluir cada um ou todos esses comandos em C++ ou C. E os comentários sobre outras linguagens

 

Definir --- declarar --- pos dentro do loop depende da lógica do programa. Entenda que uma razão para rodar um loop pode ser exatamente avaliar o valor de pos que safistaz uma condição e sair com esse valor do loop para continuar o programa

 

Ao declarar a variável no loop o escopo --- scope --- dela em C++ é o próprio loop do for e ela deixa de existir na linha seguinte e lá se vai o resultado do cálculo...

 

Pense nisso.

 

Exemplo

 

Veja a saída 

valor de pos antes do primeiro 'for' = 2019
valor de pos depois do primeiro 'for' = 2019
valor de pos depois do segundo 'for' = 3

Desse programa

#include <iostream>
using namespace std;
int main()
{
    auto pos = 2019;

    for (;0;); // irrelevante: nao faz nada
    for (;0;); // mas correto: nao faz nada

    int uns_int[] = { 1,2,3,4,5 }; primeiro valor > 3 está na posição 3

    // usando o for para determinar pos = posicao do primeiro elemento maior que 3
    cout << "valor de pos antes do primeiro 'for' = " << pos << endl;
    for (auto pos = 0; pos < 5; pos = pos + 1)
        if (uns_int[pos] > 3) break;

    cout << "valor de pos depois do primeiro 'for' = " << pos << endl;

    // o mesmo for aqui vai funcionar, sem declarar pos
    for (pos = 0; pos < 5; pos = pos + 1)
        if (uns_int[pos] > 3) break;

    cout << "valor de pos depois do segundo 'for' = " << pos << endl;
    return 0;
};  // main()

A redeclaração de pos no for faz com que a variável pos declarada antes desapareça. Ao final do for ela volta a vida com o valor de antes e seu resultado já era. No loop seguinte, como a variável não é redeclarada, tudo funciona e sai com pos = 3.

 

Por outro lado, o pos pode ser eliminado bem como o incremento e a expressão pos<16: obrigatório no for é

for(;;); // correto, mas nao termina nunca
for(;0;); // correto, roda uma vez e sai

apenas. Veja os for "mínimos" lá no programa exemplo também

 

 

 

 

  • Obrigado 1
Postado

Caro Arfneto,

 

O C/c++ permite uma flexíbilidade muito grande de implementação, e cada caso é um caso. Óbviamente que declarar int pos, dentro do loop, causa um término da instância pos assim que o bloco termina sua execução. 

 

Mas o intuito era somente mostrar.

 

abraço

adicionado 5 minutos depois
Em 11/12/2019 às 22:07, Blumer Celta disse:

Muito obrigado pelas dicas amigos...

estou conseguindo acertar agora...

este aqui funcionou muito bem para os propósitos que tenho:


  d=1;
  for(; d<=10; d++)
    printf("\n:%2i",d);

Com este já diminuiu um parâmetro e posso inicializar o loop com o valor que quiser (setando previamente a variável)

 

Opa,

 

Os compiladores C, desde dos seus primórdios implementação um série de otimizações no seu código fonte ao mesmo tempo que compilada. Logo,a forma que você fez dá na mesma que :

 

for(d=1; d<= 10; d++)

      printf("\n:%2i",d);

 

abrço

 

  • Curtir 1

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...

LANÇAMENTO!

eletronica2025-popup.jpg


CLIQUE AQUI E BAIXE AGORA MESMO!