Ir ao conteúdo
  • Cadastre-se

C Um programa que gera números primos a de um limite superior estabelecido


Joel Martins
Ir à solução Resolvido por devair1010,

Posts recomendados

Estou a tentar criar um programa para gerar números primos até um limite estabelecido pela pessoa.

Já avancei até aqui, mas empanquei na formula dos números primos.

//Programa que gera números primos a partir de um limite superior estabelecido.
#include <stdio.h>

void main()
{
    int limite,a=2,b,c;

    printf("Insere um limite-->");
    scanf("%d",&limite);

    do{
        if(b==(int)b)
        {
            
            b=a/c;
            printf("%d\n",a);
            c=a;
            a++;
        }
        else
            printf("ERRO");
    }
    while(a<limite);
}

 

Link para o comentário
Compartilhar em outros sites

  • Solução

@Joel Martins    esse título está confuso ,  e no seu código está tentando comparar a variável b com ele mesmo , e ele nem foi inicializado , assim o resultado será uma surpresa , e parece me que estas tentando descobrir se o número é inteiro ou float , e não precisa , porque na hora de pegar algum valor usando scanf , que tem entrada formatada , e o %d significa que espera receber um valor do tipo int , e caso seja inserido um valor de outro tipo , o compilador vai rejeitar ele e mostrar um bela mensagem de erro  , finalizando a execução do código ,   e caso seja gerar números de um limite inicial até um limite final ,  então poderá ser assim  :

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <math.h>
int main()
{
    int limite , a = 2, b=0, c=0,aux;

    printf("Insere um limite inicial --> ");
    scanf("%d", & a);                  //  com esse formato scanf só aceita inteiro , e nada além
    printf("Insere um limite final --> ");
    scanf("%d", &limite);              //  se inserir valor diferente de int vai dar ERRO
    a = abs(a);                        //  só vai usar numeros positivos
    limite = abs( limite );            //  só vai usar numeros positivos
    if (a > limite)                    //  se limite inferior maior que superior
    {                                  //  inverte o valor dessas duas variáveis
        aux    = a;
        a      = limite;
        limite = aux;
    }
    if (a == 1)a++;                    //  o número 1 não é primo , excluir ele
    do {                               //  todos os números entre os limite e inclusive eles
        b = 0;                         //  b será usado como contador de primos
        for (int c = 1; c <= a; c++)   //  percorre todos 
        {                              //  testando se é divisível
            if (a % c == 0)b++;        //  b eh o total de divisores
        }
        if( b < 3 )printf("%4d\n", a); //  para imprimir em colunas de até quatro digitos
        a++;
    } while (a < limite);
    return 0;
}

 

  • Curtir 1
  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

15 horas atrás, devair1010 disse:

@Joel Martins    esse título está confuso ,  e no seu código está tentando comparar a variável b com ele mesmo , e ele nem foi inicializado , assim o resultado será uma surpresa , e parece me que estas tentando descobrir se o número é inteiro ou float , e não precisa , porque na hora de pegar algum valor usando scanf , que tem entrada formatada , e o %d significa que espera receber um valor do tipo int , e caso seja inserido um valor de outro tipo , o compilador vai rejeitar ele e mostrar um bela mensagem de erro  , finalizando a execução do código ,   e caso seja gerar números de um limite inicial até um limite final ,  então poderá ser assim  :


#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <math.h>
int main()
{
    int limite , a = 2, b=0, c=0,aux;

    printf("Insere um limite inicial --> ");
    scanf("%d", & a);                  //  com esse formato scanf só aceita inteiro , e nada além
    printf("Insere um limite final --> ");
    scanf("%d", &limite);              //  se inserir valor diferente de int vai dar ERRO
    a = abs(a);                        //  só vai usar numeros positivos
    limite = abs( limite );            //  só vai usar numeros positivos
    if (a > limite)                    //  se limite inferior maior que superior
    {                                  //  inverte o valor dessas duas variáveis
        aux    = a;
        a      = limite;
        limite = aux;
    }
    if (a == 1)a++;                    //  o número 1 não é primo , excluir ele
    do {                               //  todos os números entre os limite e inclusive eles
        b = 0;                         //  b será usado como contador de primos
        for (int c = 1; c <= a; c++)   //  percorre todos 
        {                              //  testando se é divisível
            if (a % c == 0)b++;        //  b eh o total de divisores
        }
        if( b < 3 )printf("%4d\n", a); //  para imprimir em colunas de até quatro digitos
        a++;
    } while (a < limite);
    return 0;
}

 

Acabei por não entender. Eu comecei agora nestes dois ultimos 3 meses a programar pela minha primeira vez e por isso não entendi algumas coisas no programa como por exemplo:

aux

aux = a; a = limite; limite = aux;

limite = abs( limite );

#define _CRT_SECURE_NO_WARNINGS

a = abs(a);

 

Poderia explicar-me o que quer dizer e para que serve?

Obrigado.)

Link para o comentário
Compartilhar em outros sites

@Joel Martins    entendi , você ainda está iniciando em programação ,   e ali não tem nada demais , aquela variável aux " auxiliar " é uma variável qualquer e ali ela está sendo usada para armazenar o valor de uma outra variável , a variável  a  , e assim trocar os valores de  a  e limite um pelo outro , pois se o usuário digitar um valor para o primeiro scanf , que pede o número inicial  de onde vai começar a contar os primos , for maior do que  o segundo, que pede  o número final  onde vai terminar a contagem de primos ,  aí o Loop vai dar erro , e para não dar erro , o

if  

verifica isso e faz a troca do valor dessas duas variáveis , assim o Loop segue do jeito certo ,      e   o 

limite = abs(limite) 
a      = abs(a) 

é que  imagino que você queira apenas números positivos , e caso o usuário digite um valor negativo ,  essa função  "abs" , vai converter esse valor para positivo , e por isso precisa da biblioteca

#include <math.h> 

,  e o

#define _CRT_SECURE_NO_WARNINGS

  é muito útil se você estiver usando o compilador Visual Studio da Microsoft , ele é bem moderno e funciona muito bem , mas cada compilador tem seu jeito de executar as funções e o visual studio precisa desse comando e que seja colocado logo na primeira linha do código , para que algumas funções funcionem bem , como o scanf  o strcpy ,  e observando seu código vi que você pretende iniciar a partir do número dois , e o limite aí será o final onde vai terminar ,  e sendo assim não precisa daquela parte de trocar os valores das duas variáveis .

  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

@devair1010 então isso quer dizer que estar lá aux é a mesma coisa que estar lá   t   e abs tambem pode ser trocado por uma letra que eu quiser basta que ela guarde um valor.Certo?

Outra coisa...

Neste caso esta linha não era necessária pois iria começar no numero primo mais baixo que neste caso é 2

printf("Insere um limite inicial --> "); scanf("%d", & a); // com esse formato scanf só aceita inteiro , e nada além

Link para o comentário
Compartilhar em outros sites

@Joel Martins     o aux é uma variável Qualquer , sim , pode substituir ela por qualquer outra , mas o abs é uma função do próprio compilador , e nós que apenas usamos o compilador não podemos modificar esse nome , apenas quem criou o compilador pode fazer isso , mudando no código do criação do compilador .

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

@devair1010 Obrigado pela ajuda.

Eu modifiquei um🤏o programa .Veja se está correto,pff.

//Escreva um programa que gera números primos a partir de um limite superior estabelecido.
#include <stdio.h>

int main()
{
    int limite , a = 2, b=0, c=0;

                //  com esse formato scanf só aceita inteiro , e nada além
    printf("Insere um limite final --> ");
    scanf("%d", &limite);              //  se inserir valor diferente de int vai dar ERRO
do
{
    printf("Insere um numero positivo-->");
    scanf("%d", &limite);
}

while(limite<0);

    if (a == 1)a++;                    //  o número 1 não é primo , excluir ele
    do {                               //  todos os números entre os limite e inclusive eles
        b = 0;                         //  b será usado como contador de primos
        for (int c = 1; c <= a; c++)   //  percorre todos
        {                              //  testando se é divisível
            if (a % c == 0)b++;        //  b eh o total de divisores
        }
        if( b < 3 )printf("%4d\n", a); //  para imprimir em colunas de até quatro digitos
        a++;
    } while (a < limite);
    return 0;
}

 

Link para o comentário
Compartilhar em outros sites

1 hora atrás, Joel Martins disse:

Neste caso esta linha não era necessária pois iria começar no numero primo mais baixo que neste caso é 2

printf("Insere um limite inicial --> "); scanf("%d", & a); // com esse formato scanf só aceita inteiro , e nada além

sim , se você quer começar a verificar os primos , de 2 em diante , então não precisa dessas duas linhas e nem dessas 

a = abs(a);                        //  só vai usar numeros positivos
limite = abs( limite );            //  só vai usar numeros positivos
if (a > limite)                    //  se limite inferior maior que superior
{                                  //  inverte o valor dessas duas variáveis
    aux    = a;
    a      = limite;
    limite = aux;
}
if (a == 1)a++;                    //  o número 1 não é primo , excluir ele

que trocam os valores das variáveis  .

@Joel Martins     me parece bom ,  e está funcionando bem , e nesse caso não vais precisar dessas linha aqui :

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
    int limite, a = 2, b = 0, c = 0;
// pode remover essas Linhas aqui de baixo -----------------------|
    //  com esse formato scanf só aceita inteiro , e nada além    |
    printf("Insere um limite final --> ");                        |
    scanf("%d", &limite);                                         |
//----------------------------------------------------------------|      

 

testei novamente e vi um pequeno erro , que estava mostrando o dois  como primo , mesmo digitado o número hum , e modificando seu código ,  poderia assim  :

#define _CRT_SECURE_NO_WARNINGS                  // para usar scanf e outras funções no visual studio
#include <stdio.h>                               //  biblioteca padrão da linguagem c para entrada e saida de dados
int main()                                       //  melhor usar mesmo o int main , pois poderá retornar alguma coisa para o Windows
{                                                // e o void é chato e não retorna nada é inútil
    int limite, a = 1, b = 0, c = 0;             //  variuáveis locais precisam ser inicializadas as GLobais Não precisam pois são sempre zeradas
    do                                           // repite se inserir negativo
    {                                            //  essa identação me parece boa
        printf("Insere um numero positivo--> "); //  boa mensagem e um espaço para melhor visuaLização
        scanf("%d", &limite);                    //  só aceita inteiro senão erro
    } while (limite < 0);                        //  se limite menor que zero volta lá no DO
    if (limite == 1)                             //  para não dar erro na contagem de divisres
    {
        printf("\nNenhum Primo Nessa Area !\n\n\n");
        return 0;                                //  retorna para o Windows
    }
    do 
    {                                            //  todos os números entre os limite e inclusive eles
        b = 0;                                   //  b será usado como contador de primos
        for (int c = 1; c <= a; c++)             //  percorre todos
        {                                        //  testando se é divisível
            if (a % c == 0)b++;                  //  b eh o total de divisores
        }
        if (b < 3)printf("%4d\n", a);            //  para imprimir em colunas de até quatro digitos
        a++;
    } while (a < limite);
    return 0;
}

 

  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

Antes de tudo é preciso uma definição aqui: :) vai gerar os números primos

  • "até um limite estabelecido pela pessoa"
  • ou "a partir de um limite superior estabelecido"? :) 

O exercício clássico é gerar a partir de 2 até um limite N pré-estabelecido

 

Como estou á toa aguardando o churrasco vou escrever umas coisas sobre isso ;) Algumas coisas como discutidas aqui ficaram acho que um pouco "soltas".
 

Seu programa inicial não fazia sentido, mas melhorou bem tópico a tópico, talvez com as sugestões de outros, como @devair1010

 

Em 19/02/2021 às 22:21, devair1010 disse:

scanf , que tem entrada formatada , e o %d significa que espera receber um valor do tipo int , e caso seja inserido um valor de outro tipo , o compilador vai rejeitar ele e mostrar um bela mensagem de erro  , finalizando a execução do código

 

Não, não vai. O compilador vai gerar o programa apenas. Em tempo de execução o programa, e não o compilador, vai rodar o código correspondente à scanf().

Caso seja inserido um valor de outro tipo

  • o compilador não va rejeitar nada. O programa pode ter sido compilado anos atrás
  • não haverá mensagem de erro
  • o programa não vai ser finalizado, vai prosseguir cegamente a menos que se faça o simples e teste o retorno de scanf(), cujo protótipo é
     
        int scanf(const char *format, ...)

    No exemplo em #2 temos
 

    int limite , a = 2, b=0, c=0,aux;

    printf("Insere um limite inicial --> ");
    scanf("%d", & a);                  //  com esse formato scanf só aceita inteiro , e nada além
    printf("Insere um limite final --> ");
    scanf("%d", &limite);              //  se inserir valor diferente de int vai dar ERRO
    a = abs(a);                        //  só vai usar numeros positivos
    limite = abs( limite );            //  só vai usar numeros positivos

 

Sobre trechos como esse, muito comuns nestes foruns:
 

scanf() e valores sem sinal

 

Declare 

unsigned limite = 0;

e escreva

    scanf("%u", &limite);             

e o código vai cuidar de ler apenas valores positivos. No entanto scanf() em geral aceita o sinal (!!), o que leva a resultados no mínimo inesperados. Veja esse programa:
 

#include <stdio.h>
#include <stdlib.h>

int main()
{
    unsigned    valor = 0;
    int         res = 0;

    printf("valor: ");
    res = scanf("%u", &valor);
    printf( "Valor considerado: %u, res=%d\n", valor, res );
    
    valor = abs(valor);
    printf("Valor depois de abs()=%u\n", valor);
    return 0;
};

 

E esse resultado, que eu acho bem 1d10t@, para dizer o mínimo:
 

toninho@DSK-2009:~/projects/um$ gcc -o tst -Wall t.c
toninho@DSK-2009:~/projects/um$ ./tst
valor: -223
Valor considerado: 4294967073, res=1
Valor depois de abs()=223


Pela especificação está certo, mas na prática seria mais útil  scanf() retornar 0 e não 1. Qual o propósito de aceitar -223 e converter para algo positivo ao invés de rejeitar a entrada e retornar zero? Talvez Ken Thompson tenha a razão :) 

 

E se digitar algo assim
 

toninho@DSK-2009:~/projects/um$ ./tst
valor: f
Valor considerado: 0, res=0
Valor depois de abs()=0
toninho@DSK-2009:~/projects/um$ 

 

Ao entrar uma letra scanf() retorna o esperado, 0.

 

@devair1010note que em nenhum dos casos o programa cancela ou dá mensagens de erro, mas nunca vai ter um valor negativo no valor lido por scanf()

 

6 horas atrás, devair1010 disse:

o abs serve para converter um valor qualquer em  valor positivo , assim se for inserido um valor negativo , o abs vai converter ele para positivo ,  pois ainda nunca vi um número primo que seja negativo

 

 

abs(x) retorna o valor absoluto, de onde vem o nome. O valor de x desconsiderando o sinal. A definição geralmente aceita de número primo é
 

Citação

um número inteiro N maior que 1 que não possa ser escrito como produto de dois números inteiros A e B tais que A*= N.

 

Um número primo é um número que não pode ser decomposto. 15 não é primo porque pode ser escrito como 3x5, mas 13 é primo porque não existem A e B inteiro de modo que A*B = 13.

 

Mas em geral não há razão para  não estender a definição e considerar -11 primo, por exemplo, pela mesma razão: -11 só pode ser escrito como (-1) * 11 ou 1 * -(11). Então -11 não é composto. Se não é composto é primo, pode-se dizer.

 

Veja essa definição na WikiPedia por exemplo.  O estudo dos primos precede o uso de números negativos...

 

De volta aos primos

 

19 horas atrás, isrnick disse:

Se está tentando achar todos os números primos até um valor máximo o melhor é usar um método de filtragem/eliminação como o Crivo de Erastótenes.


Eu postei uma solução comentada e com resultados até um milhão por duas maneiras, em 
 

 

 

E pode ser interessante dar uma olhada. Uma das maneiras usa o crivo de Eratóstenes. E tem desenhos e referências.

 

Em 20/02/2021 às 13:36, Joel Martins disse:

#define _CRT_SECURE_NO_WARNINGS

 

Em 20/02/2021 às 13:36, Joel Martins disse:

Poderia explicar-me o que quer dizer e para que serve?


Muitas funções antigas da biblioteca de C, como scanf(), asctime() e fopen(), foram identificadas como inseguras décadas atrás. Isso porque ao não controlar tamanhos de campos e coisas assim facilitam a injeção de código, hacking. E foram criadas versões chamadas "seguras" dessas funções. São chamadas de "safe versions". Só que o padrão da linguagem C é controlado por um comitê e essas coisas são votadas e há muita discussão, política e egos envolvidos.

 

A Microsoft tentou por anos bancar a inclusão disso na norma, mas nunca teve sucesso. Mas o compilador da Microsoft reforça o uso dessas versões e não aceita essas versões inseguras de scanf() por exemplo. A razão é que scanf() ao ler uma string permite que seja invadida a memória e assim seria uma maneira de injetar código e corromper o programa ou induzir algum tipo de fraude. O tal buffer overflow...
 

Esse programa

 

#include <stdio.h>

int main()
{
    char    linha[4];
    int     res = 0;

    printf("String: ");
    res = scanf("%s", linha);
    printf("Valor lido: '%s', res=%d\n", linha, res);

    return 0;
};

 

Vai dar esse erro ao compilar:
 

 error C4996: 'scanf': This function or variable may be unsafe. Consider using scanf_s instead.
 To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.

 

E o significado da mensagem é óbvio: essa função pode ser insegura. Use scanf_s()! E veja a ajuda online para detalhes.

 

A razão: linha tem só quatro posições: char[4]. Mas o cara pode digitar 300 e inserir código dele no meio disso. Claro, hoje em dia isso é uma longa hiostória e não vou discutir isso aqui. 

 

Mas muita gente quer usar essas funções e pronto. Ou porque quer usar programas que vieram de outros sistemas, como MAC OS, ou porque estão cuidando disso de outro modo. Mas a fragilidade existe e vai dar m. no Linux, no Mac, no Windows e tal. Veja um teste no Windows:

 

image.png.f86dee1e05f2c8116249ef6d69627216.png

Note que scanf() até leu ok os quatro bytes, mas como o cara digitou um monte de m. isso corrompeu a memória....

 

Esse #define como está claro na mensagem de erro instrui o compilador para não reclamar disso e aceitar essas funções.

 

Não é preciso ter esse #define na verdade. No caso de compilar na linha de comando se pode passar o parâmetro simplesmente. No caso de usar o IDE do Visual Studio basta colocar isso nas propriedades do projeto ou usar modelos de geração de projeto que incluam essa definição

 

 

 

Veja um exemplo:

 

C:\src>cl /Wall dv.c
Microsoft (R) C/C++ Optimizing Compiler Version 19.28.29337 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

dv.c
dv.c(8): warning C4996: 'scanf': This function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
C:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\ucrt\stdio.h(1274): warning C4710: 'int scanf(const char *const ,...)': function not inlined
C:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\ucrt\stdio.h(1274): note: see declaration of 'scanf'
Microsoft (R) Incremental Linker Version 14.28.29337.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:dv.exe
dv.obj

C:\src>cl /D_CRT_SECURE_NO_WARNINGS /Wall dv.c
Microsoft (R) C/C++ Optimizing Compiler Version 19.28.29337 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

dv.c
C:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\ucrt\stdio.h(1274): warning C4710: 'int scanf(const char *const ,...)': function not inlined
C:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\ucrt\stdio.h(1274): note: see declaration of 'scanf'
Microsoft (R) Incremental Linker Version 14.28.29337.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:dv.exe
dv.obj


Ou seja: basta usar a opção /D

 

No Visual Studio a maneira mais comum é colocar nas propriedades do projeto. C/C++ Preprocessor | Preprocessor Definitions, o mesmo valor:
 

image.png.bf4b3af913ad80da6b0890c2f4b294bd.png


E usando essas scanf_s() afinal?

 

#include <stdio.h>
int main(void)
{
    char    linha[4];
    int     res = 0;
    printf("String: ");
    res = scanf_s("%s", linha, 4);
    printf("Valor lido: '%s', res=%d\n", linha, res);
    return 0;
};

 

Pois é: apenas o óbvio: depois de cada campo que vai ler você passa o tamanho dele, e assim a memória está protegida

 

 

De volta aos primos

 

7 horas atrás, Joel Martins disse:

Então qual é a função do abs?Guardar um valor?Mas para isso há o scanf

 

Não. abs() retorna o valor absoluto. scanf() lê entrada formatada: scan formatted input é a origem do nome. Não "guarda um valor".

 

 

 

O programa como está

 

O programa não está ainda muito bom.

  • Teste o retorno de scanf(). É ingênuo seguir sem testar.
  • Como está começando, se acostume a escrever na tela os valores lidos antes de começar a calcular. Assim saberá se as coisas estão indo como esperado...
  • declare uma variável por linha
  • use nomes mais expressivos para a s variáveis

 

 

  • Obrigado 2
Link para o comentário
Compartilhar em outros sites

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...