O struct nada mais é do que um "tipo" que iremos criar (como uma variável, com atributos e métodos).
Para isso, basta declarar ela, dessa forma:
#include <iostream>
using namespace std;
struct carro {
string nome;
string cor;
int pot;
int velMax;
};
int main() {
return 0;
}
Aí, já podemos declarar os atributos desse modo:
#include <iostream>
using namespace std;
struct carro {
string nome;
string cor;
int pot;
int velMax;
};
int main() {
carro car1;
car1.nome = "Tornado";
car1.cor = "Vermelho";
car1.pot = 450;
car1.velMax = 350;
cout << car1.nome << endl;
cout << car1.cor << endl;
cout << car1.pot << endl;
cout << car1.velMax << endl;
return 0;
}
Podemos criar outras variáveis dessa mesma forma.
Isso é bastante útil pra jogos, criar por exemplo, carros, competidores, inimigos e etc., utilizando arrays.
PS: Não confundir com classes, pois o struct não é característica da orientação à objetos e não permite por exemplo, encapsulamento e herança, e já existia em C. No entanto, as structs no C++ permitem criar métodos, coisa que não era possível no C, e ganham características de uma classe (com algumas limitações).
Como dito anteriormente, no C++ podemos criar métodos nas structs, vamos alterar a struct criada assim, adicionando esses métodos:
struct carro {
string nome;
string cor;
int pot;
int velMax;
int vel;
void insere(string n, string c, int p, int v) {
nome = n;
cor = c;
pot = p;
velMax = v;
vel = 0;
}
void mostra() {
cout << "Nome.............: " << nome << endl;
cout << "Cor..............: " << cor << endl;
cout << "Potência.........: " << pot << endl;
cout << "Velocidade Atual.: " << vel << endl;
cout << "Velocidade Máxima: " << velMax << endl << endl;
}
void mudaVel(int mv) {
vel = mv;
if(vel > velMax) {
vel = velMax;
}
else if(vel < 0) {
vel = 0;
}
}
};
E dessa forma, facilita criar mais variáveis do mesmo tipo, assim:
int main() {
carro car1, car2;
car1.insere("Tornado", "Vermelho", 450, 350);
car1.mudaVel(150);
car1.mostra();
car2.insere("Luxo", "Preto", 250, 260);
car2.mostra();
return 0;
}
Voltando ao código anterior, vamos fazer algumas modificações no código, vamos criar um array, assim:
int main() {
carro carros[5];
carro car1, car2, car3, car4, car5;
carros[0] = car1;
carros[1] = car2;
carros[2] = car3;
carros[3] = car4;
carros[4] = car5;
return 0;
}
E criar alguns métodos usando vetores:
int main() {
carro carros[5];
carro car1, car2, car3, car4, car5;
carros[0] = car1;
carros[1] = car2;
carros[2] = car3;
carros[3] = car4;
carros[4] = car5;
carros[0].insere("Tornado", "Vermelho", 450, 350);
carros[1].insere("Luxo", "Preto", 250, 260);
carros[2].insere("Família", "Prata", 150, 180);
carros[3].insere("Trabalho", "Branco", 80, 120);
carros[4].insere("Padrão", "Cinza", 100, 150);
return 0;
}
E para exibir, basta usarmos um laço for pra isso:
for(int i = 0; i < 5; i++) {
carros[i].mostra();
}
Simplificando:
for(carro c: carros) {
c.mostra();
}
O ponteiro é o que armazena o endereço de outra variável, uma variável que ele está apontando, ou seja, outra variável. Ela independe do escopo das outras variáveis.
Vamos supor que declaramos duas variáveis, uma do tipo int. nome num e valor 4, no endereço 1000. E criaremos uma outra variável, do tipo int e nome pn, com um asterisco *
(operador de indireção ou de referência) antes do nome (que indicará que é um ponteiro), e abaixo dela atribuimos o valor com o nome da primeira variável usando o operador &
, que indica o endereço da variável, assim:
int num = 4;
int *pn; // Criação do ponteiro.
pn = # // Atribui o endereço de num à pn (e não o valor).
cout << pn << endl; // Imprimirá o endereço de memória da variável apontada, e não o valor.
cout << *pn << endl; // Imprime o valor armazenado no endereço da variável apontada (num).
No caso acima, nos associamos o pn com a variável num através do endereço;
PS: Tanto a variável apontada quanto o ponteiro deverão ser do mesmo tipo.
Vamos criar um novo código, assim:
#include <iostream>
using namespace std;
int main() {
string veiculo = "Carro";
string *pv;
cout << veiculo << endl;
return 0;
}
Para entendermos o que acontece acima, a variável veiculo contém o valor, e o pv é um ponteiro, indicado pelo asterisco.
PS: O ponteiro não armazena o valor da variável apontada, armazena apenas o endereço de memória.
Para adicionar o endereço da outra variável no ponteiro, usamos o & (e comercial), assim:
int main() {
string veiculo = "Carro";
string *pv;
pv = &veiculo; // Ele recebe o endereço da variavel veículo, que é indicada pelo e comercial, não os valores.
cout << pv << endl; // Imprime o endereço, não o valor da variável apontada
cout << &veiculo << endl; // É o mesmo endereço acima.
return 0;
}
Com isso, podemos manipular variáveis independente do escopo das mesmas, podendo fazer isso dentro ou fora da função e tudo mais, por mexer diretamente no endereço de memória, que sempre será o mesmo durante a execução do programa. Isso cria várias possibilidades de manipulação de variáveis nos programas futuros.
Para mudar o valor da variável através do ponteiro, é simples, veja como fazemos pra mudar o valor da variável veiculo através dele:
int main() {
string veiculo = "Carro";
string *pv;
pv = &veiculo;
cout << veiculo << endl; // Imprime o valor de veiculo.
cout << *pv << endl; // Imprime também o valor de veiculo.
*pv = "Moto"; // Ele adicionará esse valor ao endereço apontado (no caso, veiculo).
cout << veiculo << endl; // Imprimiu o novo valor.
cout << *pv << endl; // Imprime também o valor de veiculo já alterado.
return 0;
}
Resumindo, o & pega o endereço de memória, ou envia conteúdos para ele.
O * pega o conteúdo que está no endereço apontado, ou envia para o mesmo.
PS: Devemos sempre colocar o endereço (&) em variáveis criadas sem ponteiro para pegar o endereço da mesma. Em variáveis criadas com ponteiros só colocamos ele para pegar o endereço de memória do ponteiro (ele sem nada tem o endereço da outra variável armazenada). Veja o exemplo abaixo:
int num = 50;
int *pont;
pont = #
cout << "Endereço de num............: " << &num << endl;
cout << "Conteúdo de num............: " << num << endl;
cout << "Endereço de pont...........: " << &pont << endl;
cout << "Endereço apontado por pont.: " << pont << endl;
cout << "Conteúdo apontado por pont.: " << *pont << endl;
PS: No final do programa, é recomendarmos usarmos o delete para excluir o ponteiro, liberando memória, assim:
delete pont;
Ah, um ponteiro sempre ocupará a quantidade fixa de 8 bytes, isso porque ele ocupa apenas o endereço de memória que aponta para outra variável, que pode ter capacidade de bytes variada, como por exemplo:
cout << sizeof(num) << endl;
cout << sizeof(pont) << endl;
Caso precise declarar um ponteiro como nulo, use NULL
e inclua a bibioteca <cstddef>
.
Para manipularmos arrays através de ponteiros é simples, vamos criar o código dessa forma abaixo:
#include <iostream>
using namespace std;
int main() {
int *p;
int vetor[10];
return 0;
}
Para atribuir ao ponteiro p o endereço do primeiro elemento do array, fazemos assim:
p = vetor; // Pode ser usado assim também, mas não é recomendado.
p = &vetor[0];
Para exibir o endereço do primeiro elemento do array, fazemos assim:
int main() {
int *p;
int vetor[10];
p = &vetor[0];
cout << p << endl;
return 0;
}
O próximo elemento do vetor sempre está no próximo endereço de memória, por regra, o que facilita a manipulação de arrays, veja o exemplo abaixo:
int main() {
int *p;
int vetor[10];
p = &vetor[0];
cout << p << endl;
p = &vetor[1];
cout << p << endl;
p = &vetor[2];
cout << p << endl;
return 0;
}
PS: A posição de endereço não é regra a sequência 1, 2, 3, etc., e sim, pelo tamanho de bytes de cada variável (o tipo int tem 4 bytes, por isso pula do 4 pro 8, e depois pro c, seguindo a contagem em hexadecimal).
Podemos também incrementar os ponteiros para exibir todos os dados do array, assim:
int main() {
int *p;
int vetor[10];
p = &vetor[0];
cout << p << endl;
*(p++);
cout << p << endl;
*(p++);
cout << p << endl;
*(p++);
cout << p << endl;
*(p++);
cout << p << endl;
return 0;
}
Pode ver que o ponteiro já incrementará os bytes automaticamente, independente do tamanho dos dados.
PS: Podemos também usar laços (como o do while ou o for) pra isso.
Para atribuir valores às posições dos arrays, fazemos assim:
int main() {
int *p;
int vetor[10];
p = &vetor[0];
*p = 10; // Atribui o valor à posição 0 do vetor.
cout << vetor[0] << endl; // Exibe o valor atribuído pelo ponteiro.
return 0;
}
No caso acima, adicionamos à posição 0 do vetor o valor, através do ponteiro p, que apontava pra posição 0 do vetor.
Da mesma forma, fazemos o mesmo com outros valores:
int main() {
int *p;
int vetor[10];
p = &vetor[0];
*p = 10;
cout << vetor[0] << endl;
*(p++);
*p = 20;
cout << vetor[1] << endl;
return 0;
}
PS: Se tentar imprimir um valor vazio do array, ele imprimirá "lixo" (algum valor inútil atribuído), tome cuidado com isso.