A linguagem C foi criada na década de 70, mas continua até hoje sendo muito utilizada, principalmente para desenvolver aplicações que requerem alto desempenho ou otimização do uso de recursos. A linguagem C, bem como a sua variante orientada a objetos (C++), é utilizada para o desenvolvimento de uma grande gama de aplicações, que vão desde softwares para controlar dispositivos embarcados (televisão, câmera digital, forno microondas etc), desenvolvimento de planilhas eletrônicas e processadores de texto, até sistemas operacionais.
C é uma linguagem de alto nível, embora apresente características de baixo nível. Dessa forma, é necessário a utilização de um compilador, para que programas escritos em C sejam convertidos para linguagem de máquina. No sistema operacional Windows o compilador usualmente utilizado é o MinGW. No Linux usualmente se usa o GNU Compiler Collection (GCC), e nos sistemas operacionais BSD e Mac OS usualmente é utilizado o CLANG/LLVM.
Antes de iniciarmos a demonstração de programas escritos em C, é importante comentar que a linguagem C é case-sensitive, ou seja, ela faz diferenciação entre letras maiúsculas e minúsculas. Dessa forma, os identificadores A
e a
, por exemplo, são diferentes.
#include <stdio.h>
int main() {
printf("Oi Mundo!!");
return 0;
}
Esse programa é muito simples e tem como resultado a saída na tela da string “Alô Mundo!!”. Vamos agora analisar linha por linha o significado dos comandos presentes nesse programa em C.
Na primeira linha temos #include <stdio.h>
, que serve para incluir a biblioteca stdio.h
. Bibliotecas implementam um conjunto de funções que podem ser usadas pelos programas C. A biblioteca stdio.h
implementa as funções de entrada e saída de dados padrão. Para usar funções de uma biblioteca é necessário incluí-la no seu programa usando a diretiva #include
. Existem diversas bibliotecas de funções disponíveis em C, como a biblioteca de funções matemáticas (math.h
), por exemplo.
Diferença em relação a Python: em Python não é necessário importar pacotes para usar as funções print()
e input()
. Em C é obrigatório importar stdio.h
para usar as funções de entrada padrão (scanf()
) e saída padrão (printf()
).
Na segunda linha temos o início da função main
, que é a função principal do programa escrito em C. O programa será executado seguindo a definição dos comandos escritos dentro dela. Ou seja, entre as chaves de abertura e fechamento ({ e }
) que delimitam a função main
deve-se colocar os comandos necessários para a resolução do problema. É importante notar que dentro da função main
pode haver a chamada de outras funções, como por exemplo, a utilização da função printf
para escrita de informações na saída padrão.
A partir da terceira linha temos as definições dos comandos que formam o programa descrito. Na terceira linha temos o primeiro comando do programa em questão. O comando é uma chamada à função printf
, que coloca a string "Oi Mundo!!" na saída padrão (terminal de execução do programa).
Diferença em relação a Python: em Python o final de uma linha de comando é definido pelo caractere que representa uma nova linha (inserido ao clicar enter). Em C é necessário informar explicitamente o final de uma linha de comando, usando ponto e vírgual (;
). Note que não é necessário colocar ;
após abertura e fechamento de chaves e também não é necessário incluir ;
após o #include
.
Na quarta linha temos o comando return 0
. O comando return
força a saída da função e retorna algum valor (exceto se a função não tiver retorno [void
]). Ou seja, quando um comando return
é executado a função é encerrada, e o valor colocado após o return
é retornado ("jogado para fora da função"). Por enquanto, tenham apenas em mente que o return
marca o fim da função main e, consequentemente, o fim do programa. Na quinta linha temos o fechamento da chave, que delimita o final do escopo da função main
.
Diferença em relação a Python: em Python o escopo é delimitado usando identação. Em C o escopo é delimitado usando abertura e fechamento de chaves. Apesar de não ser obrigatório o uso de identação, uma vez que a delimitação do escopo é feita usando as chaves, é uma boa prática de programação (eu diria uma prática obrigatória) usar a identação, de modo a tornar o código mais legível e fácil de entender.
Uma variável representa um espaço na memória e serve para armazenar dados de um determinado tipo. Na linguagem C, todas as variáveis devem ser explicitamente declaradas antes de serem usadas. Para realizar uma declaração de uma variável na linguagem C deve-se informar o tipo da variável seguido do seu identificador. Existem algumas regras para a formação dos identificadores, por exemplo:
int
, include
, void
, return
, if
, while
etc). Uma variável de determinado tipo apenas pode armazenar valores desse mesmo tipo, caso contrário haverá um erro de semântica no programa. Por exemplo, uma variável do tipo inteiro só pode armazenar valores numéricos inteiros no seu espaço de memória.
Diferença em relação a Python: Python usa tipagem dinâmica; ou seja, as variáveis podem armazenar valores de diferentes tipos no decorrer do programa. C usa tipagem estática; ou seja, uma variável que é declarada como sendo de um tipo, permanece sendo do mesmo tipo dentro do escopo a que ela pertence. Além disso, em C é necessário declarar explicitamente o tipo da variável antes de começar a usa-la. Considere os exemplos de código a seguir para somar dois números inteiros, em Python e em C, respectivamente.
a = 10
b = 20
soma = a+b
print (soma)
#include <stdio.h>
int main() {
int a = 10;
int b = 20;
int soma = a + b;
printf("%d",soma);
return 0;
}
Em Python o tipo de uma variável é definido de acordo com o tipo do valor que é atribuído a ela. Em C deve-se informar o tipo antes da definição do identificador da variável (int
no exemplo). Após a declaração da variável com um determinado tipo, caso ocorra uma atribuição posteriormente de um valor de tipo diferente a essa variável, isso causará um erro em tempo de compilação. Em Python não ocorre erro se um valor de tipo diferente for atribuído às variáveis a
ou b
posteriormente.
O exemplo de código a seguir mostra exemplos de variáveis sendo declaradas. Note que é opcional atribuir um valor inicial à variável após a declaração (no exemplo, apenas a variável b
recebe um valor inicial junto da declaração). Também é possível declarar variáveis de um mesmo tipo, uma ao lado da outra, com os identificadores separados por vírgula (como foi o caso das variáveis n1
e n2
).
#include <stdio.h>
int main() {
int a;
float b = 1.5;
char c;
int n1,n2;
return 0;
}
Um erro comumente cometido por iniciantes na linguagem C é a utilização de variáveis não inicializadas. Quando se declara uma variável, não se sabe o valor que está armazenado nela, a não ser que haja uma inicialização durante a declaração. Quando não existe uma inicialização, as variáveis armazenam no momento da declaração um valor que estava previamente na memória e que chamamos de "lixo". Por exemplo, considere o seguinte trecho de código:
...
int a, c;
c = 10 + a;
...
O valor de a
não foi inicializado, portanto é um erro utilizarmos ele na atribuição à variável c
. Como não inicializamos a
no momento da declaração, ele pode conter qualquer valor. Portanto, é importante inicializar uma variável antes de utilizá-la, com o objetivo de evitar erros no programa. A inicialização poderia ser feita da seguinte forma:
...
int a = 5, c;
c = 10 + a;
...
Nesse caso é garantido que será atribuído o valor 15 (10 + a) à variável c
, já que a variável a
foi inicializada com o valor 5.
Os tipos primitivos de uma linguagem de programação são os tipos básicos que fazem parte da definição da linguagem. À princípio apenas pode-se declarar variáveis dos tipos primitivos. No entanto, é possível criar novos tipos compostos, a partir da combinação de variáveis de tipos primitivos ou pela combinação de outras variáveis de tipos compostos. Mais na frente será mostrado como construir novos tipos compostos em C.
A Tabela a seguir mostra os tipos disponíveis em C para valores inteiros, o tamanho em memória das variáveis de cada tipo, o intervalo de valores admitidos para cada tipo, e também o código de formatação para cada um.
Tipo | Tamanho em Memória Usual (bytes) | Intervalo de Valores Usual | Código de Formatação |
---|---|---|---|
char |
1 | -128 a 127 | %hhd (como número) ou %c (como caractere) |
unsigned char |
1 | 0 a 255 | %hhd (como número) |
short |
2 | -32768 a 32767 | %hd |
unsigned short |
2 | 0 a 65535 | %hu |
int |
4 | -2147483648 a 2147483647 | %d |
unsigned int |
4 | 0 a 4294967296 | %u |
long |
8 | -9223372036854775807 a 9223372036854775808 | %ld |
unsigned long |
8 | 0 a 1,844674407370955×1019 | %lu |
long long |
8 | -9223372036854775807 a 9223372036854775808 | %lld |
unsigned long long |
8 | 0 a 1,844674407370955×1019 | %llu |
Para armazenamento de valores inteiros, a linguagem C oferece cinco tipos primitivos: char
, short
, int
, long
e long long
. O que muda de um tipo para o outro é a quantidade de bytes que uma variável irá ocupar na memória e, consequentemente, o intervalo de valores que é possível armazenar na variável. Por exemplo, variáveis do tipo short
ocupam dois bytes (16 bits) na memória. Portanto, é possível armazenar 216 = 65536 valores diferentes na memória. Caso sejam admitidos valores positivos e negativos, metade dos possíveis valores são números negativos e a outra metade números positivos (além do zero). Portanto, variáveis do tipo short
podem armazenar valores inteiros entre -32768 e 32767.
É importante notar que a quantidade de bytes associada a cada tipo depende da plataforma. Essa tabela considera um computador com processador Intel de 64 bits e o sistema operacional Mac OS 10.13. Por exemplo, em microcontroladores de 8 bits da família PIC o tipo int
ocupa apenas dois bytes (ver página 149 do manual do compilador). Portanto, caso sua aplicação seja sensível a essas diferenças, é importante verificar a definição das variáveis primitivas utilizada para a plataforma para qual a aplicação está sendo desenvolvida. O exemplo de código a seguir mostra como saber a quantidade de bytes ocupada em memória por um tipo de dados em C (usando a função sizeof()
), o que pode ser útil para desenvolver programas genéricos e que se adaptem à plataforma sendo utilizada, em alguns casos. Compile e execute esse código em sua máquina para testar.
#include <stdio.h>
int main() {
printf("Tamanho do char: %lu byte\n", sizeof(char));
printf("Tamanho do short: %lu bytes\n", sizeof(short));
printf("Tamanho do int: %lu bytes\n", sizeof(int));
printf("Tamanho do long: %lu bytes\n", sizeof(long));
printf("Tamanho do long long: %lu bytes\n", sizeof(long long));
return 0;
}
Também é importante notar que às vezes dois tipos diferentes podem ser equivalentes. Por exemplo, para a plataforma considerada para gerar a Tabela~\ref{tab:tiposinteiros} as variáveis dos tipos long
e long long
são equivalentes (ocupam 8 bytes). Em outras plataformas, uma variável do tipo int
pode ser equivalente a uma variável do tipo long
, ambas ocupando 4 bytes, enquanto que uma variável do tipo long long
ocupa 8 bytes.
É possível definir variáveis que só consideram valores positivos, usando a palavra chave unsigned
antes do tipo. Nesse caso, o intervalo de valores é dobrado para o lado positivo e os números negativos não são representados. Por exemplo, uma variável do tipo unsigned short
pode assumir valores entre 0 e 65535.
Finalmente, os códigos de formatação mostrados na última coluna são úteis para a formatação dos dados de entrada e saída, como será melhor explicado mais na frente. Como exercício, observe os exemplos de código C mostrados até o momento e identifique como os códigos de formatação foram utilizados em conjunto com a função printf()
. No exemplo de código que mostra como utilizar a função sizeof()
, é utilizado o código de formatação %lu
para representar o valor retornado pela função sizeof()
. Isso quer dizer que a resposta fornecida por essa função é do tipo unsigned long
.
Ao implementar um algoritmo para resolver algum problema deve-se ficar atento às restrições sobre os valores que podem ser atribuídos às variáveis. Por exemplo, o valor máximo que uma variável do tipo int
pode armazenar é igual a 231-1 = 2147483647. Tendo isso em mente, analise o trecho de código a seguir.
#include <stdio.h>
int main() {
long a = 3000000000;
int b = 10;
int soma = a + b;
printf("%d", soma);
return 0;
}
Ao executar o programa gerado a partir desse código, foi colocado na saída o valor -1294967286. Isso ocorreu pois os valores atribuídos às variáveis a
e soma
são maiores que o valor máximo permitido para variáveis do tipo int
. Isso é chamado de overflow. Esse tipo de erro é muito perigoso, uma vez que o código compila e executa, mas o resultado obtido é diferente do esperado. Além disso, é possível que um programa funcione para vários casos de teste (que não chegam a provocar overflow), o que pode dar a falsa impressão de que o código está correto. Troque os tipos das variáveis a
e soma
por long long
nesse exemplo de código e execute novamente para ver o resultado obtido. Lembre de modificar o código de formatação na função printf()
.
Diferença em relação a Python: no Python 2 também existem os tipos int
e long
(no Python 3 essa diferença desaparece), mas não é necessário explicitar se uma determinada variável é de um desses tipos. Dependendo do valor atribuído à variável, o tipo dela é alterado pelo interpretador. Caso os valores fiquem abaixo do limite definido para variáveis do tipo int
(esse valor é específico da plataforma em uso), as operações com os valores inteiros são realizadas utilizando as instruções para operações aritméticas disponibilizadas pelo processador. Para valores que excedam o limite máximo para variáveis int
, o interpretador precisa tratar as operações via software. À princípio, não existe limite para o tamanho dos valores inteiros usados em Python, no entanto para valores muito grandes o tempo de processamento pode ser alto, devido à necessidade de realizar processamento em software para as operações aritméticas.
char
Variáveis do tipo char
são mais comumente utilizadas para armazenar caracteres. Os caracteres em C são representados utilizando aspas simples ('
), por exemplo: 'a'
, '2'
,'#'
. Existe uma tabela chamada Tabela ASCII que faz uma associação de todos os caracteres dessa tabela com um valor numérico correspondente. Dessa forma, uma variável do tipo char
pode armazenar o valor inteiro correspondente a um determinado caractere, seguindo a tabela. Por exemplo, o caracter 'A'
é representado pelo valor 65 na tabela ASCII. Assim, uma variável do tipo char
que contenha o caractere 'A'
, na realidade armazena em memória o valor inteiro 65. O exemplo de código a seguir mostra como é possível armazenar um caractere em uma variável do tipo char
e como utilizar o printf()
para colocar na saída o caractere armazenado pela variável, bem como o valor numérico correspondente. Como demonstrado na Tabela que lista os tipos inteiros, o padrão de codificação para a variável do tipo char
no modo numérico é %hhd
, enquanto que no modo caractere é %c
.
#include <stdio.h>
int main() {
char c1 = 'C';
char c2 = 'G';
printf ("IFPB - %c%c\n", c1, c2);
printf ("Valores inteiros: %hhd %hhd\n", c1,c2);
printf ("%d\n", '#');
return 0;
}
Ao ser executado, o programa gerado por esse código coloca as seguintes infomações na saída:
IFPB - CG
Valores inteiros: 67 71
Na primeira linha os conteúdos das variáveis c1
e c2
são combinados para compor a palavra ''IFPB - CG''
, enquanto que na segunda linha os valores inteiros correspondentes aos caracteres 'C'
e 'G'
na tabela ASCII são mostrados (67 e 71).
É importante notar que devido à ampliação do conjunto de caracteres que podem ser representados, o tipo char
não é mais capaz de representar todos os caracteres existentes, mas continua sendo usado para representar o alfabeto ASCII. No entanto, grande parte dos caracteres que estamos habituados a utilizar nas línguas portuguesa e inglesa podem ser representados por ela. Para se informar mais sobre a representação de outros caracteres, pesquise sobre Tabela Unicode.
A linguagem C oferece três tipos básicos para representação de números de ponto flutuante: float
, double
e long double
. A diferença entre elas também é a quantidade de bytes que uma variável ocupa e, consequentemente, o intervalo de valores que pode ser armazenado, bem como a precisão. A Tabela a seguir mostra os tipos disponíveis em C para valores reais, o tamanho em memória das variáveis de cada tipo, o intervalo de valores admitidos para cada tipo, e também o código de formatação para cada um. Essa tabela também foi gerada considerando a mesma plataforma usada para gerar os dados da tabela que lista os tipos inteiros. Portanto, em outras plataformas as definições com relação à quantidade de bytes das variáveis de cada tipo podem variar.
Tipo | Tamanho em Memória Usual (bytes) | Intervalo de Valores Usual | Código de Formatação |
---|---|---|---|
float |
4 | 1,175494 × 10−38 a 3,402823 × 1038 | %f (notação normal) ou %e (notação científica) |
double |
8 | 2,225074 × 10−308 a 1,797693 × 10308 | %lf (notação normal) ou %le (notação científica) |
long double |
16 | 3,362103 × 10−4932 a 1,189731 × 104932 | %Lf (notação normal) ou %Le (notação científica) |
De forma similar como discutido para os números inteiros, antes de decidir qual tipo de variável utilizar para valores reais, deve-se analisar as características dos valores que precisam ser armazenados e processados pela sua aplicação. Em geral, quando uso de memória não é uma forte restrição, pode-se utilizar double
para conseguir uma boa precisão. No entanto, caso a aplicação possua requisitos críticos de memória (como pode ocorrer em muitos sistemas embarcados), deve-se avaliar se o uso de variáveis float
atendem aos requisitos de precisão dos cálculos que serão realizados, uma vez que variáveis float
ocupam a metade do espaço em memória ocupado por uma variável do tipo double
.
Outra alternativa é usar variáveis do tipo float
para armazenar os dados e utilizar variáveis do tipo double
para realizar os cálculos. Nesse último cenário pode-se minimizar as perdas de precisão durante a realização de cálculos. Isso é especialmente útil quando se realiza uma grande quantidade de cálculos sucessivos utilizando valores reais como operandos. O tempo de processamento para variáveis com maior precisão também é maior, mas nem sempre a diferença será significante. O tipo long double
é o que apresenta maior precisão e deve ser usado em aplicações que requeiram uma precisão muito grande. Na grande maioria dos casos o uso de variáveis double
resolve o problema.
Para entender melhor as diferenças, deve-se levar em consideração que variáveis do tipo float
possuem aproximadamente 7 dígitos de precisão, variáveis do tipo double
possuem aproximadamente 16 dígitos de precisão e variáveis do tipo long double
possuem aproximadamente 34 dígitos de precisão. Em resumo, caso o sistema não possua requisitos críticos de memória ou precisão, usar double
é a melhor opção. Caso o sistema possua requisitos críticos de memória, deve-se avaliar a possibilidade de utilizar variáveis do tipo float
, ao menos para armazenamento. Caso a aplicação apresente requisitos críticos de precisão, deve-se avaliar se é necessário utilizar long double
, ao menos durante o processamento dos dados (e manter double
para armazenamento).
String e booleano não possuem representação direta na linguagem C por meio de tipos primitivos. Em C, uma string é representada por um conjunto (array) de caracteres e um booleano pode ser representado por uma variável inteira. Valores inteiros diferentes de 0 equivalem ao valor booleano True e o valor 0 equivale ao valor booleano False. Arrays e strings (arrays de char
) serão estudados em mais detalhes no Capítulo 3.
Nessa seção serão apresentados mais detalhes sobre a função de saída padrão (printf()
) e será apresentada a função de entrada padrão (scanf()
).
A função printf()
permite que um conjunto de valores (constantes, variáveis ou resultados de expressões) sejam exibidos de acordo com um determinado formato. O formato geral da função printf()
é:
printf(<formato>, <lista de valores>);
O primeiro parâmetro da função printf()
(o formato) contém a cadeia de caracteres que será exibida na tela. Após o primeiro parâmetro, deve-se colocar uma lista de 0 ou mais valores (separados por vírgula). No parâmetro formato são definidos os locais dentro da cadeia de caracteres onde os valores que fazem parte da lista de valores passados como parâmetro (constantes/variáveis/resultados de expressões) serão apresentados. Para definir os locais onde os valores aparecem dentro da cadeia de caracteres, deve-se utilizar os códigos de formatação das variáveis, de acordo com os seus tipos (os códigos de formatação das variáveis primitivas foram mostrados nas tabelas apresentadas anteriormente, que listam os tipos de variáveis inteiras e reais). Considere o exemplo a seguir:
#include <stdio.h>
int main() {
int idade = 35;
float altura = 1.8;
printf("Tenho %d anos e %f metros de altura", idade, altura);
return 0;
}
Neste exemplo, são colocados dois valores na saída (um do tipo int
e um do tipo float
). No primeiro parâmetro da função printf()
é informado o formato da saída, que define a frase que será colocada na saída e os locais onde irão aparecer os dois valores (das variáveis idade
e altura
), que são informados nos parâmetros seguintes. Ao executar o programa gerado a partir desse código, é obtida a seguinte saída:
Tenho 35 anos e 1.800000 de altura
No local onde foi colocado o %d
aparece o valor que estava dentro da variável idade
e no local onde foi colocado o %f
aparece o valor que estava dentro da variável altura
. Para limitar a quantidade de casas decimais dos valores reais na saída, pode-se escrever o código de formatação na forma: %.<qtd-digitos>f
, em que <qtd-digitos>
deve ser substituído pela quantidade de casas decimais que devem aparecer, como mostrado no exemplo de código a seguir, em que o valor da altura aparece na saída com apenas duas casas decimais. No exemplo a seguir também foi colocado um caractere '\n'
ao final da string que define o formato da saída. Esse caractere serve para pular uma linha.
#include <stdio.h>
int main() {
int idade = 35;
float altura = 1.8;
printf("Tenho %d anos e %.2f metros de altura\n", idade, altura);
return 0;
}
A função de entrada padrão de C funciona de forma semelhante à função de saída. No primeiro parâmetro deve-se informar o formato da entrada, indicando os tipos dos valores que serão lidos (por meio dos códigos de formatação). Após o primeiro parâmetro, deve-se colocar os endereços das variáveis que receberão os dados da entrada. O conceito de endereço de variável será melhor explorado no Capítulo que trata de ponteiros. Neste momento, apenas lembre que o endereço de uma variável é obtido colocando um &
antes do identificador da variável. Considere o exemplo a seguir:
#include <stdio.h>
int main() {
int idade;
float altura;
scanf("%d", &idade);
scanf("%f", &altura);
printf("Tenho %d anos e %.2f metros de altura", idade, altura);
return 0;
}
Nesse exemplo, os valores de idade
e altura
são lidos da entrada usando a função scanf()
. Para a variável idade
foi usado o código de formatação %d
(variável do tipo int
) e para a variável altura
foi usado o código de formatação %f
(variável do tipo float
). Note que o segundo parâmetro da função scanf()
é o endereço das variáveis que receberão os valores lidos da entrada (&idade e &altura
). É importante ter atenção a esse detalhe, pois caso não seja colocado o &
antes do nome da variável, o código compila normalmente (provavelmente será mostrado apenas um warning), mas ocorre um erro durante a execução.
O código a seguir mostra um exemplo de como declarar uma string em C, como ler da entrada a string e como colocar na saída o conteúdo da string. Existe um código de formatação para string, que é o %s
.
#include <stdio.h>
int main() {
char nome[100];
printf ("Digite seu nome: ");
scanf("%s", nome);
printf("Nome: %s", nome);
return 0;
}
Nesse exemplo a variável nome
é um array (o conceito equivalente em Python seria lista) de 100 posições do tipo char
. Essa variável pode armazenar strings de até 99 caracteres, uma vez que um caractere deve ser reservado para indicar o final da string (esses detalhes serão melhor explorados no Capítulo 3). Por enquanto, é apenas importante aprender a declarar strings como um array de char
, ler da entrada strings e colocar na saída o conteúdo de uma string. Um diferença importante da string com relação às variáveis primitivas é que na função scanf()
não é necessário usar o &
antes do nome da variável. O motivo disso também será entendido na seção que descreve arrays e strings em mais detalhes. Nesse momento, apenas lembre que não é necessário colocar o &
no scanf()
para ler strings, mas é necessário colocar o &
para ler variáveis dos tipos primitivos.
Não há muita diferença entre os operadores aritméticos básicos utilizados em C e em Python. Em C existem os seguintes operadores aritméticos: soma (+
), subtração (-
), multiplicação (*
), divisão (/
) e resto da divisão (%
). Os operadores de multiplicação, divisão e resto de divisão possuem maior precedência em relação aos operadores de soma e subtração. Para operadores que possuem a mesma precedência, a avaliação da expressão ocorre da esquerda para a direita. Também é possível utilizar parênteses para forçar precedência entre os operadores.
Em C também são definidos operadores de incremento (++
), de decremento (--
) e operadores de atribuição. O exemplo de código a seguir exemplifica o uso desses operadores.
#include <stdio.h>
int main() {
int n1 = 0;
int n2 = 2;
n1++; //equivale a n1 = n1 + 1;
n2--; //equivale a n2 = n2 - 1;
n1 += n2; //equivale a n1 = n1 + n2;
n1 /= n2; //equivale a n1 = n1/n2;
n2 *= 3; //equivale a n2 = n2*3;
n2 %= 2; //equivale a n2 = n2%2;
printf("N1: %d\nN2: %d\n", n1,n2);
return 0;
}
Ao executar o programa gerado por esse código, obtemos a saída mostrada a seguir. Como exercício, simule o código no papel para verificar como esse resultado foi obtido.
N1: 2
N2: 1
Os operadores de incremento e decremento também podem ser usados antes da variável (ex: --n1
). Quando utilizados de forma isolada (é o caso do exemplo de código mostrado anteriormente), não faz diferença colocar o operador antes ou depois da variável, mas quando utilizado dentro de uma expressão maior, a posição do operador de incremento influencia no resultado final obtido. Mais especificamente, quando colocado antes da variável, primeiro é realizado o incremento/decremento e só após isso o valor da variável é utilizado na expressão. Quando o operador é colocado após a variável, o valor atual da variável é utilizado na expressão e só depois é realizado o incremento/decremento. Para entender melhor, considere o exemplo de código a seguir:
#include <stdio.h>
int main() {
int n = 2;
int a,b;
a = n++ - 1;
b = ++n - 1;
printf("a: %d\nb: %d\n", a,b);
return 0;
}
O programa gerado por esse código coloca na saída o seguinte:
a: 1
b: 3
Na expressão da linha 9 o incremento à variável n
é feito após a subtração. Logo, ao final dessa expressão a variável a
recebe o valor 1 (2 - 1
) e depois a variável n
passa a armazenar o valor 3. Na expressão da linha 10 o incremento à variável n
ocorre antes. Logo, primeiro n
passa a armazenar o valor 4 e depois o resto da expressão é analisada, o que culmina na atribuição do valor 3 à variável b
.
Resolver os seguintes problemas no beecrowd, usando a linguagem de programação C:
Os operadores relacionais são usados para comparar dois valores. A linguagem C oferece os seguintes operadores relacionais (iguais aos usados em Python): <
(menor que), >
(maior que), <=
(menor ou igual a), >=
(maior ou igual a), ==
(igual a), !=
(diferente de).
Os operadores relacionais mostrados servem para comparar dois valores. O resultado produzido por um operador relacional é 0 ou 1. Como em C não existe o tipo booleano, são usados inteiros para representar valores lógicos. O valor 0 corresponde a False e qualquer valor diferente de zero corresponde a True.
s operadores lógicos servem para combinar expressões relacionais e valores booleanos. A Tabela a seguir mostra os operadores lógicos existentes na linguagem C, bem como o operador equivalente em Python, para fins de comparação.
Operadores Lógicos | Em C | Em Python |
---|---|---|
não | ! |
not |
e | && |
and |
ou | || |
or |
É importante notar que os operadores lógicos e
e ou
} são representados por dois caracteres (&& e ||
). Em C existem operadores para manipular valores em nível de bit, chamados de operadores bitwise. No caso dos operadores bitwise é usado apenas um caractere para o e
e para o ou
(&
e |
). O uso de operadores bitwise está fora do escopo desta seção, mas é importante conhecer a diferença de sintaxe entre eles e os operadores lógicos. Alguns exemplos de uso dos operadores lógicos e relacionais serão mostrados no próximo Capítulo, que apresenta as estruturas de decisão e de repetição.
Diferença em relação a Python: diferente de C, em Python as expressões do tipo a < b < c
possuem a interpretação que é convencional na matemática. Em C, não é possível usar um mesmo operando para dois operadores relacionais (na expressão a < b < c
, o b
é comparado tanto com o a
como com o c
). Para escrever uma expressão como essa em C, seria necessário combinar dois operadores relacionais, usando o &&
, da seguinte forma: a < b && b < c
.