Alvaro: Resolução dos exercícios da aula 1 #8

Open
opened 2025-05-16 22:15:26 -03:00 by alvaro · 0 comments

Estou compartilhando a minha resolução para críticas, complementações e crescimento mútuo.

Linguagem C: Conceitos e Exercícios

1. Pesquise e explique.

As classificações abaixo são utilizadas para descrever as características da linguagem C: pesquise e explique cada uma delas.

a. Linguagem de alto nível

É uma linguagem mais abstrata e mais fácil de entendimento para os humanos. Ela se concentra em conceitos mais próximos da linguagem humana como variáveis, loops e funções. As linguagens de alto nível são usadas para a maioria das aplicações de programação. Elas são mais fáceis de aprender e usar do que as linguagens de baixo nível, e permitem que os programadores se concentrem no algoritmo do programa, deixando os detalhes técnicos para a linguagem de programação.

b. Linguagens Compilada

É aquela em que o código fonte é traduzido para uma linguagem de baixo nível antes da execução, gerando um arquivo que pode ser executado diretamente pelo sistema operacional. O processo de compilação pode levar mais tempo que o processo de interpretação, mas o código resultante tende a ser mais rápido e eficiente em termos de recursos.

c. Linguagem Procedural

Se baseia no conceito de procedimentos, que são conjuntos de instruções que dizem ao computador o que fazer passo a passo. Algumas características são estruturas de controle que direcionam o fluxo de execução do programa, modularidade que permite dividir o programa em partes menores para organização e reutilização do código e encapsulamento que oculta complexidades, combinando dados e funções em um módulos, reduzindo a complexidade.

d. Linguagem imperativa

Se baseia em descrever detalhadamente o passo a passo de um processo que a máquina deve executar, ou seja, as instruções são passadas por meio de códigos na sequência que devem ser executadas.

e. Linguagem estruturada

Visa a qualidade, clareza e eficiência de programas por meio da utilização de sub-rotinas e três estruturas básicas: sequência, seleção (if e switch) e iteração (laços for e while), evitando ou proibindo saltos incondicionais no código pelo uso do comando "goto", pois isso costuma tornar o código confuso e difícil de manter.

2. Analise o programa.

Dado o programa abaixo (salve.c), explique cada uma perguntas nos comentários.

#include <stdio.h> // O que é isso e para que serve? 
// Por que todo o programma é escrito na função 'main()'?
int main(void) {
    puts("Salve, simpatia!"); // O que faz e como se usa a função 'puts()'?
    return 0; // Para que serve esta instrução? 
}

a. #include <stdio.h> // O que é isso e para que serve?

O código-fonte é o código do programa escrito numa linguagem de programação, ele é legível para humanos, mas incompreensível para o computador. O compilador é um programa que traduz o código-fonte para o código objeto e transforma o código objeto em código executável. O código objeto é o código em linguagem de máquina, mas ainda incompleto e incapaz de funcionar. O código executável é o código completo e capaz de ser executado pelo sistema operacional, por ser o resultado da ligação do código objeto com bibliotecas externas e outras dependências. O pré-processador é um programa auxiliar que roda antes do compilador, preparando o código-fonte para a compilação. O símbolo # no início de linha indica uma diretiva de pré-processador, como: #include, #define e #ifdef. A diretiva #include indica que o compilador deve incluir o conteúdo de determinado arquivo. Os limitadores <> indicam que o arquivo deve ser procurado nas pastas padrão do sistema, enquanto os limitadores "" indicam que o arquivo deve primeiro ser procurado na pasta do programa e depois nas pastas padrão. O nome de arquivo stdio vem de standard input/output e h de header file. O arquivo stdio.h contém declarações de funções de entrada e saída padrão construídas em cima da biblioteca padrão do sistema operacional. A biblioteca padrão traduz funções de alto nível em chamadas de sistema usando a API do sistema operacional.

b. Por que todo o programa é escrito na função 'main()'?

Porque a função main é o porta de entrada e de saída de um programa em C. Pode haver funções auxiliares fora da função main, mas o sistema operacional não pode acessá-las diretamente, ele só as acessa se houver chamadas a elas dentro da função main. A função main coordena toda a execução do programa, isto é, a execução de comandos contidos dentro dela e as chamadas a funções externas.

c. O que faz e como se usa a função 'puts()'?

A função puts, put string, imprime uma string na tela e adiciona uma quebra de linha no final. Ela é uma instrução de saída padrão que é declarada quando o pré-processador inclui o conteúdo do arquivo stdio.h no código do programa. A função puts recebe como argumento strings entre aspas duplas ou variáveis do tipo char[]. A função puts não é capaz de lidar com variáveis numéricas ou não textuais.

d. return 0; // Para que serve esta instrução?

Ela serve para informar ao sistema operacional que a execução do programa terminou corretamente sem erros. O valor 0 significa que tudo terminou como esperado, qualquer valor diferente de zero indica erro ou uma situação diferente do normal. O sistema operacional usa esse retorno para agir de acordo, por exemplo, em scripts que executam vários programas o sistema operacional usa esse retorno para saber se o programa anterior terminou bem para poder rodar o próximo. Em sistemas baseados em Unix é padrão considerar 0 como sucesso e qualquer outro valor como erro. Em alguns compiladores do C moderno é assumido que o retorno é 0 mesmo que o comando não seja colocado, mas é uma boa prática colocar o comando explicitamente ao final da função main.

3. Compile, encontre, explique e corrija os bugs.

O uso de números mágicos (valores literais que não dão pistas de seus significados) é desaconselhado porque dificultam a leitura semântica do código. Sendo assim, nós utilizaremos a constante simbólica EXIT_SUCCESS, definida na biblioteca padrão com valor 0, em vez do inteiro literal 0 como argumento da instrução return:

#include <stdio.h>

int main(void) {
   puts("Salve, simpatia!");
   return EXIT_SUCCESS
}

Observe o resultado da compilação:

:~$ gcc salve.c -o salve

a. Quantos erros foram encontrados e quais são eles?

alvaro@dinosaur:~/estudo/debxp/cblc_resolucoes$ gcc salve.c -o salve
salve.c: In function 'main':
salve.c:5:12: error: 'EXIT_SUCCESS' undeclared (first use in this function)
    5 |     return EXIT_SUCCESS
      |            ^~~~~~~~~~~~
salve.c:2:1: note: 'EXIT_SUCCESS' is defined in header '<stdlib.h>'; did you forget to '#include <stdlib.h>'?
    1 | #include <stdio.h>
  +++ |+#include <stdlib.h>
    2 | 
salve.c:5:12: note: each undeclared identifier is reported only once for each function it appears in
    5 |     return EXIT_SUCCESS
      |            ^~~~~~~~~~~~
salve.c:5:24: error: expected ';' before '}' token
    5 |     return EXIT_SUCCESS
      |                        ^
      |                        ;
    6 | }
      | ~                       

O primeiro erro ocorreu na linha 5, caractere 12.
O segundo erro na linha 5, caractere 24.

O compilador também fez sugestões sobre o tratamento dos erros.
A correção sugerida ao tratamento do primeiro erro deveria ser posta na linha 2, caractere 1.
A correção sugerida ao tratamento do segundo erro deveria ser posta na linha 5, caractere 24.

Houve também o aviso de que o compilador indica o identificador não declarado apenas uma vez para cada função que ele aparece. Isso é feito para evitar poluir a tela com o mesmo erro repetido várias vezes na mesma função.

b. Quais são as correções sugeridas pelo gcc?

A primeira correção diz que EXIT_SUCCESS está definico no arquivo de cabeçalho stdlib.h e sugere escrever #include <stdlib.h> na linha 2, caractere 1.

salve.c:2:1: note: 'EXIT_SUCCESS' is defined in header '<stdlib.h>'; did you forget to '#include <stdlib.h>'?
    1 | #include <stdio.h>
  +++ |+#include <stdlib.h>
    2 |

A segunda correção diz que o caractere ; era esperado antes do símbolo } e sugere escrever um ; na linha 5, caractere 24.

salve.c:5:24: error: expected ';' before '}' token
    5 |     return EXIT_SUCCESS
      |                        ^
      |                        ;
    6 | }
      | ~

c. Como ficou o código corrigido?

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

int main(void) {
    puts("Salve, simpatia!");
    return EXIT_SUCCESS;
}

4. Compile, pesquise e responda.

Dado o código abaixo (por exemplo, main.c):

#define EXIT_SUCCESS 0

int puts(const char *string);

int main(void) {
    puts("Salve, simpatia!");
    return EXIT_SUCCESS;
}

Compilação:

:~$ gcc main.c
:~$

a. Nenhum erro foi reportado, mas por quê?

Primeiro motivo. O código de main.c não inclui o arquivo stdio.h, mas declara a função puts manualmente para o compilador. Por isso, o compilador aceita a chamada da função puts mesmo sem saber onde ela está definida, nem o seu código. O compilador só sabe o nome da função puts, que ela recebe um ponteiro para uma string constante e que retorna um inteiro. O código real da função puts é buscado na etapa de ligação pelo linker na biblioteca padrão do C.

Segundo motivo. O código de main.c não inclui o arquivo stdlib.h, mas define manualmente a constante EXIT_SUCCESS como 0. Assim o compilador sabe que toda vez que encontrar a constante EXIT_SUCCESS deve substituí-la por 0.

Em programas reais é uma boa prática incluir stdio.h e stdlib.h, pois esses arquivos garantem que o compilador use as declarações corretas, portáveis e padronizadas de funções e constantes. Declarar funções e constantes manualmente pode causar erros, incompatibilidades, falta de portabilidade e bugs difíceis de identificar, principalmente em projetos grandes ou ao trocar de plataforma.

b. Como você executaria o binário resultante?

./a.out

5. Pesquise e responda

Quando não explicitamos a especificação utilizada para compilar o nosso programa (opção -std=PADRÃO do gcc), qual será o padrão utilizado e como podemos confirmar isso pela linha de comandos?

O padrão depende da versão do GCC, mas hoje geralmente é gnu17.

Isso pode ser confirmado pelo comando:

echo | gcc -dM -E -x c - | grep __STDC_VERSION__

Se a resposta for #define __STDC_VERSION__ 201710L indica que o padrão é C17, 201710L = outubro de 2017, data em que o padrão C17 foi finalizado.

Para garantir um padrão específico o comando é:

gcc -std=c99 meu_programa.c -o meu_programa
Estou compartilhando a minha resolução para críticas, complementações e crescimento mútuo. # Linguagem C: Conceitos e Exercícios ## 1. Pesquise e explique. As classificações abaixo são utilizadas para descrever as características da linguagem C: pesquise e explique cada uma delas. ### a. Linguagem de alto nível É uma linguagem mais abstrata e mais fácil de entendimento para os humanos. Ela se concentra em conceitos mais próximos da linguagem humana como variáveis, loops e funções. As linguagens de alto nível são usadas para a maioria das aplicações de programação. Elas são mais fáceis de aprender e usar do que as linguagens de baixo nível, e permitem que os programadores se concentrem no algoritmo do programa, deixando os detalhes técnicos para a linguagem de programação. ### b. Linguagens Compilada É aquela em que o código fonte é traduzido para uma linguagem de baixo nível antes da execução, gerando um arquivo que pode ser executado diretamente pelo sistema operacional. O processo de compilação pode levar mais tempo que o processo de interpretação, mas o código resultante tende a ser mais rápido e eficiente em termos de recursos. ### c. Linguagem Procedural Se baseia no conceito de procedimentos, que são conjuntos de instruções que dizem ao computador o que fazer passo a passo. Algumas características são estruturas de controle que direcionam o fluxo de execução do programa, modularidade que permite dividir o programa em partes menores para organização e reutilização do código e encapsulamento que oculta complexidades, combinando dados e funções em um módulos, reduzindo a complexidade. ### d. Linguagem imperativa Se baseia em descrever detalhadamente o passo a passo de um processo que a máquina deve executar, ou seja, as instruções são passadas por meio de códigos na sequência que devem ser executadas. ### e. Linguagem estruturada Visa a qualidade, clareza e eficiência de programas por meio da utilização de sub-rotinas e três estruturas básicas: sequência, seleção (if e switch) e iteração (laços for e while), evitando ou proibindo saltos incondicionais no código pelo uso do comando "goto", pois isso costuma tornar o código confuso e difícil de manter. ## 2. Analise o programa. Dado o programa abaixo (salve.c), explique cada uma perguntas nos comentários. ```c #include <stdio.h> // O que é isso e para que serve? // Por que todo o programma é escrito na função 'main()'? int main(void) { puts("Salve, simpatia!"); // O que faz e como se usa a função 'puts()'? return 0; // Para que serve esta instrução? } ``` ### a. #include <stdio.h> // O que é isso e para que serve? O código-fonte é o código do programa escrito numa linguagem de programação, ele é legível para humanos, mas incompreensível para o computador. O compilador é um programa que traduz o código-fonte para o código objeto e transforma o código objeto em código executável. O código objeto é o código em linguagem de máquina, mas ainda incompleto e incapaz de funcionar. O código executável é o código completo e capaz de ser executado pelo sistema operacional, por ser o resultado da ligação do código objeto com bibliotecas externas e outras dependências. O pré-processador é um programa auxiliar que roda antes do compilador, preparando o código-fonte para a compilação. O símbolo # no início de linha indica uma diretiva de pré-processador, como: #include, #define e #ifdef. A diretiva #include indica que o compilador deve incluir o conteúdo de determinado arquivo. Os limitadores <> indicam que o arquivo deve ser procurado nas pastas padrão do sistema, enquanto os limitadores "" indicam que o arquivo deve primeiro ser procurado na pasta do programa e depois nas pastas padrão. O nome de arquivo stdio vem de standard input/output e h de header file. O arquivo stdio.h contém declarações de funções de entrada e saída padrão construídas em cima da biblioteca padrão do sistema operacional. A biblioteca padrão traduz funções de alto nível em chamadas de sistema usando a API do sistema operacional. ### b. Por que todo o programa é escrito na função 'main()'? Porque a função main é o porta de entrada e de saída de um programa em C. Pode haver funções auxiliares fora da função main, mas o sistema operacional não pode acessá-las diretamente, ele só as acessa se houver chamadas a elas dentro da função main. A função main coordena toda a execução do programa, isto é, a execução de comandos contidos dentro dela e as chamadas a funções externas. ### c. O que faz e como se usa a função 'puts()'? A função puts, put string, imprime uma string na tela e adiciona uma quebra de linha no final. Ela é uma instrução de saída padrão que é declarada quando o pré-processador inclui o conteúdo do arquivo stdio.h no código do programa. A função puts recebe como argumento strings entre aspas duplas ou variáveis do tipo char[]. A função puts não é capaz de lidar com variáveis numéricas ou não textuais. ### d. return 0; // Para que serve esta instrução? Ela serve para informar ao sistema operacional que a execução do programa terminou corretamente sem erros. O valor 0 significa que tudo terminou como esperado, qualquer valor diferente de zero indica erro ou uma situação diferente do normal. O sistema operacional usa esse retorno para agir de acordo, por exemplo, em scripts que executam vários programas o sistema operacional usa esse retorno para saber se o programa anterior terminou bem para poder rodar o próximo. Em sistemas baseados em Unix é padrão considerar 0 como sucesso e qualquer outro valor como erro. Em alguns compiladores do C moderno é assumido que o retorno é 0 mesmo que o comando não seja colocado, mas é uma boa prática colocar o comando explicitamente ao final da função main. ## 3. Compile, encontre, explique e corrija os bugs. O uso de números mágicos (valores literais que não dão pistas de seus significados) é desaconselhado porque dificultam a leitura semântica do código. Sendo assim, nós utilizaremos a constante simbólica EXIT_SUCCESS, definida na biblioteca padrão com valor 0, em vez do inteiro literal 0 como argumento da instrução return: ```c #include <stdio.h> int main(void) { puts("Salve, simpatia!"); return EXIT_SUCCESS } ``` Observe o resultado da compilação: ``` :~$ gcc salve.c -o salve ``` ### a. Quantos erros foram encontrados e quais são eles? ``` alvaro@dinosaur:~/estudo/debxp/cblc_resolucoes$ gcc salve.c -o salve salve.c: In function 'main': salve.c:5:12: error: 'EXIT_SUCCESS' undeclared (first use in this function) 5 | return EXIT_SUCCESS | ^~~~~~~~~~~~ salve.c:2:1: note: 'EXIT_SUCCESS' is defined in header '<stdlib.h>'; did you forget to '#include <stdlib.h>'? 1 | #include <stdio.h> +++ |+#include <stdlib.h> 2 | salve.c:5:12: note: each undeclared identifier is reported only once for each function it appears in 5 | return EXIT_SUCCESS | ^~~~~~~~~~~~ salve.c:5:24: error: expected ';' before '}' token 5 | return EXIT_SUCCESS | ^ | ; 6 | } | ~ ``` O primeiro erro ocorreu na linha 5, caractere 12. O segundo erro na linha 5, caractere 24. O compilador também fez sugestões sobre o tratamento dos erros. A correção sugerida ao tratamento do primeiro erro deveria ser posta na linha 2, caractere 1. A correção sugerida ao tratamento do segundo erro deveria ser posta na linha 5, caractere 24. Houve também o aviso de que o compilador indica o identificador não declarado apenas uma vez para cada função que ele aparece. Isso é feito para evitar poluir a tela com o mesmo erro repetido várias vezes na mesma função. ### b. Quais são as correções sugeridas pelo gcc? A primeira correção diz que EXIT_SUCCESS está definico no arquivo de cabeçalho stdlib.h e sugere escrever #include <stdlib.h> na linha 2, caractere 1. ``` salve.c:2:1: note: 'EXIT_SUCCESS' is defined in header '<stdlib.h>'; did you forget to '#include <stdlib.h>'? 1 | #include <stdio.h> +++ |+#include <stdlib.h> 2 | ``` A segunda correção diz que o caractere ; era esperado antes do símbolo } e sugere escrever um ; na linha 5, caractere 24. ``` salve.c:5:24: error: expected ';' before '}' token 5 | return EXIT_SUCCESS | ^ | ; 6 | } | ~ ``` ### c. Como ficou o código corrigido? ```c #include <stdio.h> #include <stdlib.h> int main(void) { puts("Salve, simpatia!"); return EXIT_SUCCESS; } ``` ## 4. Compile, pesquise e responda. Dado o código abaixo (por exemplo, main.c): ```c #define EXIT_SUCCESS 0 int puts(const char *string); int main(void) { puts("Salve, simpatia!"); return EXIT_SUCCESS; } ``` Compilação: ``` :~$ gcc main.c :~$ ``` ### a. Nenhum erro foi reportado, mas por quê? Primeiro motivo. O código de main.c não inclui o arquivo stdio.h, mas declara a função puts manualmente para o compilador. Por isso, o compilador aceita a chamada da função puts mesmo sem saber onde ela está definida, nem o seu código. O compilador só sabe o nome da função puts, que ela recebe um ponteiro para uma string constante e que retorna um inteiro. O código real da função puts é buscado na etapa de ligação pelo linker na biblioteca padrão do C. Segundo motivo. O código de main.c não inclui o arquivo stdlib.h, mas define manualmente a constante EXIT_SUCCESS como 0. Assim o compilador sabe que toda vez que encontrar a constante EXIT_SUCCESS deve substituí-la por 0. Em programas reais é uma boa prática incluir stdio.h e stdlib.h, pois esses arquivos garantem que o compilador use as declarações corretas, portáveis e padronizadas de funções e constantes. Declarar funções e constantes manualmente pode causar erros, incompatibilidades, falta de portabilidade e bugs difíceis de identificar, principalmente em projetos grandes ou ao trocar de plataforma. ### b. Como você executaria o binário resultante? ``` ./a.out ``` ## 5. Pesquise e responda Quando não explicitamos a especificação utilizada para compilar o nosso programa (opção -std=PADRÃO do gcc), qual será o padrão utilizado e como podemos confirmar isso pela linha de comandos? O padrão depende da versão do GCC, mas hoje geralmente é gnu17. Isso pode ser confirmado pelo comando: ``` echo | gcc -dM -E -x c - | grep __STDC_VERSION__ ``` Se a resposta for `#define __STDC_VERSION__ 201710L` indica que o padrão é C17, 201710L = outubro de 2017, data em que o padrão C17 foi finalizado. Para garantir um padrão específico o comando é: ``` gcc -std=c99 meu_programa.c -o meu_programa ```
alvaro changed title from Minha resolução dos exercícios da aula 1 to Alvaro: Resolução dos exercícios da aula 1 2025-05-16 22:37:52 -03:00
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: blau_araujo/cblc#8
No description provided.