C stdlib.h e stdio.h
Esta é a página de consulta rápida das duas bibliotecas que quase todo programa em C inclui. O <stdlib.h> ("standard library", biblioteca padrão) tem memória dinâmica, conversão de texto em número, números aleatórios, ordenação e o encerramento do programa. O <stdio.h> ("standard input/output", entrada e saída padrão) tem a tela, o teclado e os arquivos. Cada linha das tabelas leva à aula que explica a função com calma. Os formatos do printf e do scanf estão em printf e scanf.
Todas as saídas foram produzidas de verdade: no gcc 15.2 da máquina da Ana (Linux de 64 bits, pasta ~/c/ref, comando gcc -std=c23 -Wall -Wextra) e no editor do guia (Clang em WebAssembly). Quando os dois diferem, a tabela diz.
Atalhos: stdlib.h: Memória · Texto → número · Ordenar, buscar, contas · Aleatórios · Encerrar e ambiente · stdio.h: Tela e teclado · fopen e os modos · Arquivos · Constantes · Editor × gcc · Erros comuns · Experimente
stdlib.h: memória dinâmica
A memória dinâmica é a que o programa pede durante a execução, do tamanho que precisar, no heap (aula Pilha e Heap). Toda memória pedida tem de ser devolvida com free.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int *v = malloc(3 * sizeof *v);
if (v == NULL) {
return 1;
}
v[0] = 10; v[1] = 20; v[2] = 30;
int *maior = realloc(v, 5 * sizeof *v);
if (maior == NULL) {
free(v);
return 1;
}
v = maior;
v[3] = 40; v[4] = 50;
printf("realloc: %d %d %d %d %d\n", v[0], v[1], v[2], v[3], v[4]);
free(v);
double *z = calloc(4, sizeof *z);
if (z == NULL) {
return 1;
}
printf("calloc: %.1f %.1f %.1f %.1f\n", z[0], z[1], z[2], z[3]);
free(z);
char *gigante = malloc(300u * 1024 * 1024);
printf("malloc de 300 MB: %s\n", gigante ? "deu certo" : "NULL");
free(gigante);
void *alinhado = aligned_alloc(64, 128);
printf("aligned_alloc(64, 128): múltiplo de 64? %s\n", (unsigned long)alinhado % 64 == 0 ? "sim" : "não");
free(alinhado);
free(NULL);
printf("free(NULL): não faz nada\n");
return 0;
}
$ gcc -std=c23 -Wall -Wextra mem.c -o mem $ ./mem realloc: 10 20 30 40 50 calloc: 0.0 0.0 0.0 0.0 malloc de 300 MB: deu certo « no editor: NULL (o limite é 256 MB) aligned_alloc(64, 128): múltiplo de 64? sim free(NULL): não faz nada
| Função | O que faz | Devolve | Exemplo | Aula |
|---|---|---|---|---|
malloc(n)"memory allocation" | Reserva n bytes. O conteúdo é lixo. | o endereço, ou NULL se não deu | int *v = malloc(3 * sizeof *v); | malloc e free |
calloc(qtd, tam)"cleared allocation" | Reserva qtd × tam bytes, todos zerados. | o endereço, ou NULL | calloc(4, sizeof(double)) → 0.0 0.0 0.0 0.0 | calloc e realloc |
realloc(p, n) | Muda o tamanho do bloco p para n bytes, mantendo o conteúdo (pode mudar o bloco de lugar). | o novo endereço, ou NULL (aí o bloco antigo continua valendo) | de 3 para 5 int: 10 20 30 40 50 | calloc e realloc |
free(p) | Devolve o bloco. Depois disso, p não pode mais ser usado. free(NULL) não faz nada. | nada | free(v); v = NULL; | Vazamentos |
aligned_alloc(al, n) C11 | Como malloc, mas o endereço é múltiplo de al. | o endereço, ou NULL | aligned_alloc(64, 128) | Pilha e Heap |
Sempre teste o NULL. E nunca escreva v = realloc(v, n): se o realloc falhar, você perde o único endereço do bloco antigo (vazamento). Use uma variável nova, como maior no programa acima.
stdlib.h: texto → número
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int main(void) {
printf("atoi(\"42abc\") = %d\n", atoi("42abc"));
printf("atoi(\"abc\") = %d\n", atoi("abc"));
printf("atof(\"3.14\") = %g\n", atof("3.14"));
char *fim;
long n = strtol(" -17 kg", &fim, 10);
printf("strtol: %ld, sobrou [%s]\n", n, fim);
printf("strtol base 16: %ld\n", strtol("ff", NULL, 16));
printf("strtol base 2: %ld\n", strtol("1010", NULL, 2));
printf("strtol base 0: %ld %ld %ld\n", strtol("0x1F", NULL, 0), strtol("017", NULL, 0), strtol("17", NULL, 0));
n = strtol("abc", &fim, 10);
printf("strtol(\"abc\"): %ld, nada lido: %s\n", n, *fim == 'a' ? "sim" : "não");
errno = 0;
long long g = strtoll("99999999999999999999", NULL, 10);
printf("strtoll grande demais: %lld, ERANGE: %s\n", g, errno == ERANGE ? "sim" : "não");
unsigned long u = strtoul("4000000000", NULL, 10);
printf("strtoul: %lu\n", u);
double d = strtod("12.90 reais", &fim);
printf("strtod: %.2f, sobrou [%s]\n", d, fim);
float f = strtof("1e3", NULL);
printf("strtof: %.1f\n", f);
return 0;
}
$ gcc -std=c23 -Wall -Wextra conv.c -o conv
$ ./conv
atoi("42abc") = 42
atoi("abc") = 0
atof("3.14") = 3.14
strtol: -17, sobrou [ kg]
strtol base 16: 255
strtol base 2: 10
strtol base 0: 31 15 17
strtol("abc"): 0, nada lido: sim
strtoll grande demais: 9223372036854775807, ERANGE: sim
strtoul: 4000000000
strtod: 12.90, sobrou [ reais]
strtof: 1000.0
A saída do editor é idêntica.
| Função | Converte para | Se o texto não é um número | Exemplo → resultado | Aula |
|---|---|---|---|---|
atoi(s), atol(s), atoll(s)"ASCII to integer" | int, long, long long | devolve 0, calado (não dá para saber se era "0") | atoi("42abc") → 42; atoi("abc") → 0 | Texto ↔ Número |
atof(s) | double | devolve 0.0, calado | atof("3.14") → 3.14 | Texto ↔ Número |
strtol(s, &fim, base)"string to long" | long | devolve 0 e fim aponta para o começo de s; se o número não cabe, devolve LONG_MAX/LONG_MIN e põe ERANGE no errno | strtol(" -17 kg", &fim, 10) → -17, fim = " kg" | Texto ↔ Número |
strtoll, strtoul, strtoull | long long, unsigned long, unsigned long long | como strtol | strtoll("99999999999999999999", …) → 9223372036854775807 + ERANGE | Validar a Entrada |
strtod(s, &fim), strtof, strtold | double, float, long double | como strtol | strtod("12.90 reais", &fim) → 12.90, fim = " reais" | Texto ↔ Número |
A base do strtol | Entende | Exemplo → resultado |
|---|---|---|
10 | decimal | "17" → 17 |
16 | hexadecimal, com ou sem 0x | "ff" → 255 |
2 | binário | "1010" → 10 |
0 | decide pelo começo: 0x = hexadecimal, 0 = octal, o resto = decimal | "0x1F" → 31; "017" → 15; "17" → 17 |
Prefira as strto… às ato…: só elas dizem onde a leitura parou (fim) e se o número estourou (errno). Para um int, leia com strtol e confira se o valor está entre INT_MIN e INT_MAX (veja Tipos e Limites). O caminho inverso, número → texto, é o snprintf.
stdlib.h: ordenar, buscar e contas com inteiros
#include <stdio.h>
#include <stdlib.h>
int comparar(const void *a, const void *b) {
int x = *(const int *)a, y = *(const int *)b;
return (x > y) - (x < y);
}
int main(void) {
printf("abs(-5) = %d, labs(-5L) = %ld, llabs(-5LL) = %lld\n", abs(-5), labs(-5L), llabs(-5LL));
div_t r = div(17, 5);
printf("div(17, 5): quot = %d, rem = %d\n", r.quot, r.rem);
int notas[] = {7, 3, 9, 1, 5};
qsort(notas, 5, sizeof notas[0], comparar);
printf("qsort: %d %d %d %d %d\n", notas[0], notas[1], notas[2], notas[3], notas[4]);
int chave = 7;
int *achou = bsearch(&chave, notas, 5, sizeof notas[0], comparar);
printf("bsearch(7): posição %td\n", achou - notas);
chave = 4;
printf("bsearch(4): %s\n", bsearch(&chave, notas, 5, sizeof notas[0], comparar) ? "achou" : "NULL");
printf("getenv(\"HOME\") = %s\n", getenv("HOME"));
printf("getenv(\"NAO_EXISTE\") = %s\n", getenv("NAO_EXISTE") ? "achou" : "NULL");
printf("EXIT_SUCCESS = %d, EXIT_FAILURE = %d\n", EXIT_SUCCESS, EXIT_FAILURE);
printf("RAND_MAX = %d\n", RAND_MAX);
printf("MB_CUR_MAX = %zu\n", MB_CUR_MAX);
return 0;
}
$ gcc -std=c23 -Wall -Wextra misc.c -o misc
$ ./misc
abs(-5) = 5, labs(-5L) = 5, llabs(-5LL) = 5
div(17, 5): quot = 3, rem = 2
qsort: 1 3 5 7 9
bsearch(7): posição 3
bsearch(4): NULL
getenv("HOME") = /home/ana
getenv("NAO_EXISTE") = NULL
EXIT_SUCCESS = 0, EXIT_FAILURE = 1
RAND_MAX = 2147483647
MB_CUR_MAX = 1
A saída do editor é idêntica (lá, o HOME também é /home/ana).
| Função | O que faz | Exemplo → resultado | Aula |
|---|---|---|---|
qsort(v, qtd, tam, cmp)"quick sort" | Ordena um array qualquer. cmp é uma função sua que recebe dois const void * e devolve negativo, 0 ou positivo. | {7, 3, 9, 1, 5} → 1 3 5 7 9 | Ordenação (qsort) |
bsearch(&chave, v, qtd, tam, cmp)"binary search" | Procura num array já ordenado, com a mesma cmp. | 7 → ponteiro para a posição 3; 4 → NULL | Busca (bsearch) |
abs(x), labs, llabs"absolute" | Valor absoluto (sem sinal) de um int, long, long long. Para double, é o fabs do math.h. | abs(-5) → 5 | Matemática |
div(a, b), ldiv, lldiv | Quociente e resto de uma vez, numa struct (.quot, .rem). | div(17, 5) → quot = 3, rem = 2 | Aritméticos |
A comparação (x > y) - (x < y) devolve −1, 0 ou 1 sem risco. O atalho return x - y; funciona com notas, mas estoura com números grandes de sinais opostos (aula Inteiros).
stdlib.h: números aleatórios
| Função ou constante | O que faz | Exemplo | Aula |
|---|---|---|---|
rand() | Devolve um inteiro "aleatório" de 0 a RAND_MAX. A sequência é sempre a mesma se a semente for a mesma. | rand() % 6 + 1 → um dado, de 1 a 6 | Números Aleatórios |
srand(semente)"seed rand" | Escolhe a semente. Chame uma vez, no começo do programa. | srand((unsigned)time(NULL)); (precisa de <time.h>) | Números Aleatórios |
RAND_MAX | O maior valor do rand(). | 2147483647 nos dois | Números Aleatórios |
Os números mudam entre o editor e o gcc: com srand(42), os três primeiros rand() dão 311430560 131117839 1110653038 no editor e 1483128881 708592740 71876166 no gcc. O rand() não serve para senhas nem sorteios sérios.
stdlib.h: encerrar o programa e falar com o sistema
#include <stdio.h>
#include <stdlib.h>
void tchau(void) {
printf("tchau (registrada primeiro)\n");
}
void salvar(void) {
printf("salvando (registrada depois)\n");
}
int main(void) {
atexit(tchau);
atexit(salvar);
printf("trabalhando...\n");
exit(3);
}
$ gcc -std=c23 -Wall -Wextra saida.c -o saida $ ./saida; echo "código: $?" trabalhando... salvando (registrada depois) tchau (registrada primeiro) código: 3
No editor, igual, com [código de saída: 3] no fim. As funções do atexit rodam na ordem contrária à do registro.
| Função ou constante | O que faz | Exemplo | Aula |
|---|---|---|---|
exit(código) | Encerra o programa de qualquer ponto: roda as funções do atexit, esvazia os buffers e fecha os arquivos. O código vai para o $? do terminal (de 0 a 255). | exit(3) → código: 3 | exit e atexit |
EXIT_SUCCESS, EXIT_FAILURE | Os códigos de "deu certo" e "deu errado". | 0 e 1 nos dois | exit e atexit |
atexit(f) | Registra uma função void f(void) para rodar no fim (no exit ou no return do main). | ordem contrária: salvar, depois tchau | exit e atexit |
abort() | Mata o programa na hora, sem atexit e sem esvaziar buffers. | Abortado (imagem do núcleo gravada), código 134 | Sinais |
quick_exit(c), at_quick_exit(f) C11; _Exit(c) C99 | Saídas rápidas: quick_exit só roda as funções do at_quick_exit; _Exit não roda nada. | raras | exit e atexit |
getenv(nome)"get environment" | Lê uma variável de ambiente. | getenv("HOME") → /home/ana; uma que não existe → NULL | getenv |
system(comando) | Roda um comando do terminal e espera ele acabar. | system("ls"). No editor, não há terminal: sai sh: 1: ls: not found e devolve 32512 | Processos |
stdio.h: tela e teclado
A tela é o stdout, o teclado é o stdin e as mensagens de erro vão para o stderr (aula stdin, stdout e stderr). As funções com f recebem um FILE * e servem para qualquer um dos três e para arquivos.
| Função | O que faz | Devolve | Aula |
|---|---|---|---|
printf(fmt, …), fprintf(arq, fmt, …) | Escreve com formato (tabela dos formatos). | bytes escritos, ou negativo | printf |
snprintf(buf, tam, fmt, …) C99 | Escreve com formato numa string, sem passar de tam. | bytes que precisaria | Texto ↔ Número |
puts(s) | Escreve s e pula linha. | não negativo, ou EOF | printf |
fputs(s, arq) | Escreve s sem pular linha. | não negativo, ou EOF | Escrever Arquivos |
putchar(c), fputc(c, arq), putc | Escreve um caractere. | o caractere, ou EOF | char |
scanf(fmt, …), fscanf(arq, fmt, …), sscanf(s, fmt, …) | Lê com formato (do teclado, de um arquivo, de uma string). | campos lidos, ou EOF | scanf |
fgets(buf, tam, arq) | Lê uma linha inteira (com o '\n'), no máximo tam - 1 bytes. Para o teclado: fgets(buf, sizeof buf, stdin). | buf, ou NULL no fim | fgets |
getchar(), fgetc(arq), getc | Lê um caractere. Guarde num int, não num char, para caber o EOF. | o caractere, ou EOF | char |
ungetc(c, arq) | Devolve um caractere à entrada: a próxima leitura o lê de novo. | c, ou EOF | Validar a Entrada |
perror(texto) | Escreve no stderr: texto: mensagem do errno. | nada | errno e perror |
fflush(arq) | Manda já o que está no buffer de saída. fflush(stdin) não é do C: não use. | 0, ou EOF | stdin, stdout e stderr |
setvbuf(arq, buf, modo, tam) | Escolhe o buffer: _IONBF (nenhum), _IOLBF (por linha), _IOFBF (cheio). | 0 se deu certo | stdin, stdout e stderr |
gets(buf) | Removida no C11. Não sabia o tamanho do buf. No C23, nem compila (veja abaixo). | — | Segurança |
stdio.h: fopen e os modos
FILE *f = fopen("compras.txt", "r"); abre um arquivo e devolve um FILE * (um "ponteiro de arquivo", que você passa para as outras funções), ou NULL se não deu. Sempre teste o NULL e feche com fclose(f). Aula: Arquivos.
| Modo | Para | Se o arquivo não existe | Se já existe | Começa em |
|---|---|---|---|---|
"r" | ler ("read") | NULL (No such file or directory) | abre | no começo |
"w" | escrever ("write") | cria | apaga tudo e começa vazio | no começo |
"a" | acrescentar ("append") | cria | mantém | no fim (toda escrita vai para o fim) |
"r+" | ler e escrever | NULL | mantém | no começo |
"w+" | escrever e ler | cria | apaga tudo | no começo |
"a+" | ler e acrescentar | cria | mantém | lê de qualquer lugar; escreve no fim |
"wx", "w+x" C11 | criar um arquivo novo | cria | NULL (File exists): não apaga nada | no começo |
b no modo ("rb", "wb", "ab"…) | arquivo binário | No Linux não muda nada; no Windows, desliga a troca de \n por \r\n. Use em fread/fwrite. Aula: Arquivos Binários. | ||
stdio.h: ler, escrever e andar no arquivo
#include <stdio.h>
int main(void) {
FILE *f = fopen("compras.txt", "w");
if (f == NULL) {
perror("compras.txt");
return 1;
}
fprintf(f, "arroz\nfeijão\n");
fputs("café\n", f);
fclose(f);
f = fopen("compras.txt", "a");
fputc('p', f);
fputs("ão\n", f);
fclose(f);
f = fopen("compras.txt", "r");
char linha[50];
while (fgets(linha, sizeof linha, f) != NULL) {
printf("lido: %s", linha);
}
printf("feof = %d, ferror = %d\n", feof(f) != 0, ferror(f) != 0);
fseek(f, 0, SEEK_END);
printf("tamanho: %ld bytes\n", ftell(f));
rewind(f);
int c = fgetc(f);
ungetc(c, f);
printf("primeira letra: %c, de novo: %c\n", c, fgetc(f));
fclose(f);
if (fopen("compras.txt", "wx") == NULL) {
perror("modo \"wx\"");
}
if (rename("compras.txt", "lista.txt") == 0) {
printf("rename: ok\n");
}
if (fopen("compras.txt", "r") == NULL) {
perror("compras.txt");
}
printf("remove: %d\n", remove("lista.txt"));
printf("remove de novo: %d\n", remove("lista.txt"));
return 0;
}
$ gcc -std=c23 -Wall -Wextra arq.c -o arq $ ./arq lido: arroz lido: feijão lido: café lido: pão feof = 1, ferror = 0 tamanho: 25 bytes primeira letra: a, de novo: a modo "wx": File exists rename: ok compras.txt: No such file or directory remove: 0 remove de novo: -1
A saída do editor é idêntica (os arquivos ficam numa pasta em memória, que começa limpa a cada Rodar). O tamanho, 25 bytes, é a soma de 18 letras, 4 \n e mais 1 byte para cada uma das 3 letras acentuadas (que ocupam 2 bytes).
| Função | O que faz | Devolve | Aula |
|---|---|---|---|
fopen(nome, modo) | Abre (tabela dos modos). | FILE *, ou NULL | Arquivos |
fclose(f) | Fecha: grava o que estava no buffer e libera o FILE. | 0, ou EOF | Arquivos |
fgets, fgetc, fscanf | Leem uma linha, um caractere, com formato. | veja acima | Ler Arquivos |
fprintf, fputs, fputc | Escrevem com formato, uma string, um caractere. | veja acima | Escrever Arquivos |
fread(buf, tam, qtd, f) | Lê qtd itens de tam bytes, do jeito que estão na memória (binário). | quantos itens leu (size_t) | Arquivos Binários |
fwrite(buf, tam, qtd, f) | Escreve qtd itens de tam bytes. | quantos itens escreveu | Arquivos Binários |
fseek(f, desloc, origem) | Vai para outra posição: desloc bytes a partir de SEEK_SET (começo), SEEK_CUR (onde está) ou SEEK_END (fim). | 0 se deu certo | fseek e ftell |
ftell(f) | A posição atual, em bytes desde o começo. Depois de fseek(f, 0, SEEK_END), é o tamanho do arquivo. | long, ou -1 | fseek e ftell |
rewind(f) | Volta ao começo (e limpa o feof). | nada | fseek e ftell |
feof(f), ferror(f) | Dizem se uma leitura já bateu no fim, ou se deu erro. Use depois que a leitura falhou, para saber o motivo. | não zero = sim | Ler Arquivos |
clearerr(f) | Limpa os indicadores de fim e de erro. | nada | Ler Arquivos |
remove(nome) | Apaga o arquivo. | 0, ou não zero (aqui, -1) | Arquivos |
rename(velho, novo) | Muda o nome (ou a pasta) do arquivo. | 0, ou não zero | Arquivos |
tmpfile() | Cria um arquivo temporário, apagado ao fechar. Não existe no editor (erro do ligador undefined symbol: tmpfile). | FILE *, ou NULL | Arquivos |
Constantes do stdio.h
#include <stdio.h>
int main(void) {
printf("EOF = %d\n", EOF);
printf("BUFSIZ = %d\n", BUFSIZ);
printf("FILENAME_MAX = %d\n", FILENAME_MAX);
printf("FOPEN_MAX = %d\n", FOPEN_MAX);
printf("SEEK_SET = %d, SEEK_CUR = %d, SEEK_END = %d\n", SEEK_SET, SEEK_CUR, SEEK_END);
printf("_IOFBF = %d, _IOLBF = %d, _IONBF = %d\n", _IOFBF, _IOLBF, _IONBF);
return 0;
}
| Constante | O que é | gcc 15 (glibc) | Editor (wasi-libc) |
|---|---|---|---|
EOF | "end of file": o valor que as leituras devolvem no fim da entrada | -1 | -1 |
NULL | o ponteiro nulo (também em stdlib.h, string.h, stddef.h) | veja Ponteiro Nulo | |
BUFSIZ | um bom tamanho de buffer para setvbuf | 8192 | 1024 |
FILENAME_MAX | tamanho de array que cabe o maior nome de arquivo | 4096 | 4096 |
FOPEN_MAX | quantos arquivos abertos ao mesmo tempo, no mínimo, são garantidos | 16 | 1000 |
SEEK_SET, SEEK_CUR, SEEK_END | as origens do fseek | 0, 1, 2 | 0, 1, 2 |
_IOFBF, _IOLBF, _IONBF | os modos do setvbuf | 0, 1, 2 | 0, 1, 2 |
TMP_MAX, L_tmpnam | limites do tmpnam (nomes temporários) | 238328, 20 | não existem (use of undeclared identifier 'TMP_MAX') |
Escreva o nome da constante, nunca o número: while ((c = getchar()) != EOF), e não != -1.
Editor × gcc
| Assunto | Editor (Clang + wasi-libc) | gcc 15 (glibc) |
|---|---|---|
strtol("3000000000", NULL, 10) | 2147483647 e ERANGE (o long tem 4 bytes) | 3000000000, sem erro (o long tem 8) |
malloc de 300 MB | NULL (limite de 256 MB) | funciona |
srand(42) + rand() | 311430560 131117839 1110653038 | 1483128881 708592740 71876166 |
system("ls") | sh: 1: ls: not found, devolve 32512 | roda o ls |
tmpfile, tmpnam, TMP_MAX | não existem | existem |
BUFSIZ, FOPEN_MAX | 1024, 1000 | 8192, 16 |
free duplo | passa calado | free(): double free detected in tcache 2 + Abortado (134) |
| Arquivos | numa pasta em memória (/home/ana), limpa a cada Rodar | no disco, na pasta atual |
Iguais nos dois: as conversões ato…/strto… (fora o tamanho do long), qsort, bsearch, abs, div, atexit/exit, getenv("HOME"), EOF, RAND_MAX, os modos do fopen e as mensagens do perror.
Erros comuns
#include <stdlib.h> (e usou gets)
#include <stdio.h>
int main(void) {
int *v = malloc(10 * sizeof *v);
char nome[20];
gets(nome);
free(v);
return 0;
}
$ gcc -std=c23 -Wall -Wextra semstdlib.c -o semstdlib
semstdlib.c: In function ‘main’:
semstdlib.c:4:14: error: implicit declaration of function ‘malloc’ [-Wimplicit-function-declaration]
4 | int *v = malloc(10 * sizeof *v);
| ^~~~~~
semstdlib.c:2:1: note: include ‘<stdlib.h>’ or provide a declaration of ‘malloc’
1 | #include <stdio.h>
+++ |+#include <stdlib.h>
2 |
semstdlib.c:4:14: warning: incompatible implicit declaration of built-in function ‘malloc’ [-Wbuiltin-declaration-mismatch]
4 | int *v = malloc(10 * sizeof *v);
| ^~~~~~
semstdlib.c:4:14: note: include ‘<stdlib.h>’ or provide a declaration of ‘malloc’
semstdlib.c:6:5: error: implicit declaration of function ‘gets’; did you mean ‘fgets’? [-Wimplicit-function-declaration]
6 | gets(nome);
| ^~~~
| fgets
semstdlib.c:7:5: error: implicit declaration of function ‘free’ [-Wimplicit-function-declaration]
7 | free(v);
| ^~~~
semstdlib.c:7:5: note: include ‘<stdlib.h>’ or provide a declaration of ‘free’
semstdlib.c:7:5: warning: incompatible implicit declaration of built-in function ‘free’ [-Wbuiltin-declaration-mismatch]
semstdlib.c:7:5: note: include ‘<stdlib.h>’ or provide a declaration of ‘free’
No editor (Clang):
semstdlib.c:4:14: error: call to undeclared library function 'malloc' with type 'void *(__size_t)' (aka 'void *(unsigned long)'); ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration] semstdlib.c:4:14: note: include the header <stdlib.h> or explicitly provide a declaration for 'malloc' semstdlib.c:6:5: error: use of undeclared identifier 'gets' semstdlib.c:7:5: error: call to undeclared library function 'free' with type 'void (void *)'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
O que significa: o malloc e o free moram no <stdlib.h>; sem ele, o compilador não os conhece. Os dois compiladores até dizem qual #include falta (o gcc mostra a linha com +++ |+). Já o gets foi removido do C: não existe em nenhum cabeçalho.
Como consertar: acrescente #include <stdlib.h> e troque gets(nome) por fgets(nome, sizeof nome, stdin). Aulas: Protótipos e fgets.
while (!feof(f)) leu a última nota duas vezes
#include <stdio.h>
int main(void) {
FILE *f = fopen("notas.txt", "w");
if (f == NULL) {
return 1;
}
fprintf(f, "7\n9\n");
fclose(f);
f = fopen("notas.txt", "r");
if (f == NULL) {
return 1;
}
int nota = 0, soma = 0;
while (!feof(f)) {
fscanf(f, "%d", ¬a);
printf("leu %d\n", nota);
soma += nota;
}
printf("soma = %d\n", soma);
fclose(f);
return 0;
}
$ gcc -std=c23 -Wall -Wextra feof.c -o feof $ ./feof leu 7 leu 9 leu 9 soma = 25
O que significa: o feof não adivinha o futuro. Depois de ler o 9, ainda sobrou o \n, então o fim não foi alcançado. A volta seguinte chama fscanf, que falha (devolve EOF) e não muda nota: o 9 é somado de novo. Sem aviso nenhum, nos dois compiladores.
Como consertar: o teste é o retorno da leitura: while (fscanf(f, "%d", ¬a) == 1), ou while (fgets(linha, sizeof linha, f) != NULL). É a missão abaixo. Aula: Ler Arquivos.
NULL do fopen ou do malloc
Se o arquivo não existe, fopen devolve NULL, e o primeiro fgets(linha, 50, f) com esse f derruba o programa com Falha de segmentação (139), no gcc e no editor. Como consertar: if (f == NULL) { perror("compras.txt"); return 1; }, que mostra compras.txt: No such file or directory. Aula: errno e perror.
char c = getchar() num laço até EOF
O getchar devolve int porque o EOF (−1) precisa ser diferente de todos os 256 caracteres. Guardado num char, o EOF se confunde com o byte 255 (ou nunca é visto, se o char não tem sinal). Como consertar: int c;. Aula: char.
Experimente
Missão: o arquivo notas.txt (na outra aba) tem as notas 7 e 9, mas o programa soma 25, porque usa while (!feof(f)). Troque a condição do laço pelo retorno do fscanf (== 1), apague o fscanf de dentro do laço e faça o programa mostrar soma = 16.
#include <stdio.h>
int main(void) {
FILE *f = fopen("notas.txt", "r");
if (f == NULL) {
perror("notas.txt");
return 1;
}
int nota = 0, soma = 0;
while (!feof(f)) {
fscanf(f, "%d", ¬a);
printf("leu %d\n", nota);
soma += nota;
}
printf("soma = %d\n", soma);
fclose(f);
return 0;
}
7 9
#include <stdio.h>
int main(void) {
FILE *f = fopen("notas.txt", "r");
if (f == NULL) {
perror("notas.txt");
return 1;
}
int nota = 0, soma = 0;
while (fscanf(f, "%d", ¬a) == 1) {
printf("leu %d\n", nota);
soma += nota;
}
printf("soma = %d\n", soma);
fclose(f);
return 0;
}
Resumo
- stdlib.h:
malloc/calloc/realloc/free(teste oNULL; todomalloctem o seufree);strtol/strtod(melhores queatoi/atof);qsort/bsearch;abs/div;rand/srand;exit/atexit/abort;getenv/system. - stdio.h:
printf/puts/putcharescanf/fgets/getcharpara tela e teclado;fopen("r","w"apaga,"a"acrescenta,"x"não apaga) efclose;fread/fwritepara binário;fseek/ftell/rewind;remove/rename;perror. - Leia em laço pelo retorno da leitura, nunca com
while (!feof(f)). - No editor, o
longtem 4 bytes (ostrtolestoura antes) e omallocvai até 256 MB.