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 16: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)

Expandir  

 

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"

Expandir  

 

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
  Em 16/12/2019 às 15:29, Venus Guy disse:
Expandir  

 

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 14:23, Blumer Celta disse:

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

{

    //função a ser executada

}

Expandir  

 

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
  Em 19/12/2019 às 22:56, 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

Expandir  

 

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 12/12/2019 às 01: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)

Expandir  

 

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

Mostrar 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

Mostrar mais  
×
×
  • Criar novo...

LANÇAMENTO!

eletronica2025-popup.jpg


CLIQUE AQUI E BAIXE AGORA MESMO!