DCC003: Algoritmos e Estruturas de Dados I
2013/1

Exercícios 4: Ponteiros e erros comuns em C

Exercício 1. Considere o trexo de código abaixo:

        char string1[128];
        printf("digite uma palavra:\n");
        fgets(string1, 128, stdin);
        *(strchr(string1, '\n')) = '\0';

Explique, passo a passo, o que faz a última linha *(strchr(string1, '\n')) = '\0'. Consute a documentação da função strchr aqui.

(1) strchr(string1, '\n') retorna um ponteiro para a primeira ocorrência de quebra de linha ('\n') em string1. (2) *(x) = '\0' coloca o caractere terminador '\0' na posição apontada por x. (3) No caso, *(strchr(string1, '\n')) = '\0' coloca o caractere terminador '\0' na posição onde ocorre a primeira ocorrência de quebra de linha em string1. Esse comando efetivamente retira o caractere '\n' de string1 substituindo-o pelo caractere terminador '\0'.

Exercício 2. Todos os programas abaixo têm um erro. Explique detalhadamente o erro e como consertá-lo. Você pode baixar o código fonte dos programas para testá-los aqui.

Programa 1

#include <stdio.h>
int main(int argc, char **argv)
{
	int i = 0;
	int j = 0;
	int contador = 0;
	for(i = 0; i < 10; i++)
		for(j = 0; j < 10; j++);
			contador++;
	printf("contador = %d\n", contador);
	printf("pressione qualquer tecla para terminar\n");
	getc(stdin);
        return 0;
}

Esse programa tem um ponto-e-vírgula depois do segundo for. Isso faz com que o segundo for tenha um bloco de comandos vazio. O comando contador++ está fora dos dois fors e é executado apenas uma vez.

Programa 2

#include <stdio.h>
int main(int argc, char **argv)
{
	int i;
	int soma;
	for(i = 0; i < 10; i++) {
		soma += 10;
	}
	printf("10 * 10 = %d\n", soma);
	printf("pressione qualquer tecla para terminar\n");
	getc(stdin);
        return 0;
}

A variável soma não é inicializada. O resultado impresso no printf não é definido.

Programa 3

#include <stdio.h>
int main(int argc, char **argv)
{
	char linha[128];
	int num;
	int resto;
	printf("digite um numero:\n");
	fgets(linha, 128, stdin);
	sscanf(linha, "%d\n", &num);
	resto = num % 2;
	if(resto = 0) {
		printf("num eh par\n");
	} else {
		printf("num eh impar\n");
	}
	printf("pressione qualquer tecla para terminar\n");
	getc(stdin);
        return 0;
}

O if não está usando o operador de comparação (==), mas sim o operador de atribuição (=). Neste caso, a expressão resto = 0 coloca o valor zero na variável resto. O valor dessa expressão, utilizado no if, é zero (falso). Logo, essa função sempre imprime "num eh impar".

Programa 4

#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
	char string1[128];
	char string2[128];
	printf("digite uma palavra:\n");
	fgets(string1, 128, stdin);
	*(strchr(string1, '\n')) = '\0';
	printf("digite outra palavra:\n");
	fgets(string2, 128, stdin);
	*(strchr(string2, '\n')) = '\0';
	if(string1 == string2) {
		printf("strings %s e %s sao iguais\n", string1, string2);
	} else {
		printf("strings %s e %s sao diferentes\n", string1, string2);
	}
	printf("pressione qualquer tecla para terminar\n");
	getc(stdin);
        return 0;
}

A expressão string1 == string2 converte o nome string1 e string2 para a posição de memória das variáveis string1[0] e string2[0] (as primeiras variáveis em cada vetor), depois compara as duas posições de memória. A expressão no if deveria testar se os caracteres nos vetores string1 e string2 são os mesmos (por exemplo, usando a função strcmp), não comparar as posições de memória.

Programa 5

#include <stdio.h>
int main(int argc, char **argv)
{
	int numbers[10];
	int i;
	for(i = 0; i <= 10; i++) {
		numbers[i] = 0;
	}
	printf("pressione qualquer tecla para terminar\n");
	getc(stdin);
        return 0;
}

Esse programa escreve zero na posição de memória numbers[10], que não faz parte do vetor. No caso, se i for alocado logo depois do vetor numbers na memória do computador, colocar zero na posição numbers[10] é equivalente a colocar zero na variável i e o programa entra em loop infinito.

Programa 6

#include <stdio.h>
int main(int argc, char **argv)
{
	char palavra[128];
	palavra[0] = 'b';
	palavra[1] = 'a';
	palavra[2] = 'n';
	palavra[3] = 'a';
	palavra[4] = 'n';
	palavra[5] = 'a';
	printf("{{{%s}}}\n", palavra);
	printf("pressione enter para terminar\n");
	getc(stdin);
        return 0;
}

Esse programa não termina o string "banana" com o caractere terminador '\0'. Neste caso, o printf pode imprimir uma quantidade arbitrária de lixo até encontrar um caractere terminador. Se nenhum caractere terminador for encontrado o programa travará quando fizer acesso além da memória dele.

Programa 7

#include <stdio.h>
int main(int argc, char **argv)
{
	char palavra[5] = "hello";
	int i = -1;
	printf("%d {{{%s}}}\n", i, palavra);
	printf("pressione enter para terminar\n");
	getc(stdin);
        return 0;
}

Problema similar ao do exercício 6; a palavra "hello" não tem o caractere terminador '\0' porque o arranjo não tem espaço sufiente para armazenar os seis caracteres necessários.