RSS

Arquivo mensal: outubro 2011

Saindo dos pesadelos com ponteiros

Geralmente meio acadêmico da uma explicação de ponteiros deixando todos enrolados com apenas o básico , o que faz todos desviar do caminho dos ponteiros , os poucos que usam são aqueles que tem sido autodidata, bom alguns livros tem exemplos bons de ponteiros como no livro Ansi C do K&R, entretanto a falta de popularidade de tais dicas torna tal assunto meio obscuro…

*Perguntas frenéticas
Por que usar ponteiros ?
–Desempenho e maior manipulação dos dados,  fácil para depurar problemas…
E se eu não usar ?
–Na depuração de códigos STACK é bem complicada comparada com HEAP(uso do malloc(),sbrk()..), no tratamento de dados gigantes poderá ter algumas Traps Malditas!… (sim com alloca() pode usar ponteiro entretanto usaria STACK)
neca-elm-street-1-600x420

O que é ponteiro ?
Nada mais é que uma refêrencia , um tipo de dado que aponta dados que estão armazenados na memória, ponteiros são uma abstração da capacidade de endereçamento fornecidas pelas arquiteturas modernas. Em termos simples, um endereço de memória, ou índice numérico, é definido para cada unidade de memória no sistema, no qual a unidade é tipicamente um byte ou uma word, o que em termos práticos transforma toda a memória em um grande vetor.1 Logo, a partir de um endereço, é possível obter do sistema o valor armazenado na unidade de memória de tal endereço. O ponteiro é um tipo de dado que armazena um endereço…

Vamos a um exemplo básico para depois ver algo complexo

#include <stdio.h>
#include <string.h>

int main()
{
// ponteiro com int
 int *x,*y; // antes de usar um ponteiro é bom inicializar com "NULL", mas como é apenas exemplo de começo fica sem ;-[

// fazemos o casting para ponteiro de int
 x=(int *)256;
 y=(int *)256;
// casting para int antes da adição
 printf("%d \n",((int)x)+((int)y));

 puts("digite um numero para adicao com y...");
 scanf("%d",&x);
 printf("%d \n",((int)x)+((int)y));

// ponteiro com strings...
 char *word;

 word="ola";
 puts(word);
 word="lol";
 puts(word);
// 0[l] 1[o] 2[l]   word[2] logo temos "l"
 printf("char: %c \n",*(word+2));

 return 0;
}

vamos entender algumas práticas comuns de se ver depois e partir para exemplos

 int i           //Int variável 'i'
 int *p          //'P' ponteiro para um int
 int a[]         //Matriz 'a' de Int
 int f()         //'F' função com valor de retorno do tipo int
 int **p         //'Pp' ponteiro para um ponteiro para um int
 int (*pa)[]     //'Pa' ponteiro para um array de int
 int (*pf)()     //pf ponteiro para uma função com valor de retorno int
 int *p[]       //Array 'p' de ponteiros para um int
 int *var()       //Função "var", que retorna um ponteiro para um int
 int ***var       //'var' ponteiro para um ponteiro para um ponteiro para um int
 int (**var)[]  //'var' ponteiro para um ponteiro para um array de int
 int (**var)()  //'var' ponteiro para um ponteiro para uma função com valor de retorno do tipo int
 int *(*c)[]  //'c' ponteiro para uma matriz de ponteiros para um int
 int *(*c)()  //"c 'ponteiro para uma função com valor de retorno do tipo ponteiro para um int
 int **app[]    //'App' ponteiro para um ponteiro para uma matriz de ponteiros para um int
 int (*b[])[] //Uma série de 'b' ponteiros para um array de int
 int (*c[])() /Um array 'c' ponteiros para uma função com valor de retorno do tipo int
 int ***fpp()   //"Fpp 'função que retorna um ponteiro para um ponteiro para um ponteiro para um int
 int (*fpa())[] //Função 'fpa ", que retorna um ponteiro para um array de int
 int (*fpf())() //"FPF" função que retorna um ponteiro para uma função com valor de retorno int

Fique calmo não é para decorar , tenha em mente leitura da esquerda para direita, e sempre começando pelo nome da variável…

Uma prática muito comum em C é usar void pointer, para muitos que estão iniciando não é normal, entretanto estudando códigos de terceiros pode-se ver muito , usar ponteiro colabora no desempenho e o código em
Assembly gerado fica menor de fato,um “disassemble main” no GDB pode te dar ponto empírico.

Um exemplo vale mais do que mil palavras:

// exemplo void pointer by Cooler_
#include <stdio.h>

//ideia de polimorfismo
void foo(void *point,int size)
{
// int == 4 bytes
 if(size==sizeof(int))
//tem que fazer casting do ponteiro para STDOUT
  printf("int : %d , bytes: %d\n",*(int *)point,sizeof(point));

// double == 8 bytes
 if(size==sizeof(double))
//casting de novo para o write(1...
  printf("double : %f , bytes: %d\n",*(double *)point,sizeof(double));
}

int main()
{
 int a=64;
 double b=3.14;

 printf("bytes do void : %d\n",sizeof(void));
// & usamos para dizer o endereço da memória de determinada variável
 foo(&a,sizeof(int));
 foo(&b,sizeof(double));

 return 0;
}

Outro exemplo seguindo a mesma lógica

#include <stdio.h>
#include <string.h>

typedef struct _myst
{
 int a;
 char b[10];
}myst;

void func(myst *mt)
{
 printf("resposta %d %s \n",mt->a,mt->b);
}

int main()
{
 void (*resposta)(void *);

 myst x;
 x.a=4;
 strncpy(x.b,"1234",9);
 resposta = (void*)func;
 resposta(&x);

 return 0;
}

Outra prática muito vista é o “ponteiro de arrays para funções“,
vejamos terceiro exemplo:

// example pointer of arrays to function by Cooler_
#include <stdio.h>
#include <malloc.h>

void foo1(int x)
{
 printf("int: %d\n",x);
}

void foo2(int x)
{
 printf("num: %d\n",x);
}

void foo3(int z)
{
 printf("result %d\n",z*z);
}

void func2func(void (*fp)(void *), void *q)
{
  fp(q);
}

int main()
{
//se a função tiver mais de um argv use "," (int,char...
 void (**list)(int);
//alocamos 3 endereços na heap
 list=(void *)malloc(3*sizeof(void *));

 list[0]=foo1;
 list[0](2);
 list[1]=foo2;
 list[1](4);
 list[2]=foo3;
 list[2](8);

 // função para função lol
 func2func(foo2, 4);

 free(list);
 return 0;
}

Outro exemplo usando função com argumento para função:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define w printf
#define MAX_BUF 128
#define array_num(array) (sizeof(array) / sizeof *(array))

void bubble(void *p, int width, int N,int(*fptr)(const void *, const void *));
int compara_letras(const void *m, const void *n);
int compara_numeros(const void *m, const void *n);

int main()
{
 int lista[]={4,2,1,5,3,8,10,9,0,45};
 char nomes[6][20] = {"Madruga","Arara","Zebra","Elefante","Babaca","Gato"};
 short i;

 for(i=0; i<=array_num(lista)-1; i++)
  w("%d\n",lista[i]);
 for(i=0; i<=array_num(nomes)-1; i++)
  w("%s\n",nomes[i]);
 w("--------------\nagora dando buble sort nas listas\n");
 bubble(lista, 4, 10, compara_numeros);
 bubble(nomes, 20, 6, compara_letras);
 for(i=0; i<=9; i++)
  w("%d\n",lista[i]);
 for(i=0; i<=5; i++)
  w("%s\n",nomes[i]);

 return 0;
}

// função com argumento para função
void bubble(void *p, int width, int N, int(*fptr)(const void *, const void *))
{
 int i, j, k;
 unsigned char buf[MAX_BUF];
 unsigned char *bp = p;
  for(i = N-1; i >= 0; i--)
  {
   for(j = 1; j <= i; j++)
   {
//repare que fptr é a função escolhida pelo usuário
    k = fptr((void *)(bp + width*(j-1)), (void *)(bp + j*width));
    if(k > 0)
    {
     memcpy(buf, bp + width*(j-1), width);
     memcpy(bp + width*(j-1), bp + j*width , width);
     memcpy(bp + j*width, buf, width);
    }
   }
  }
}
//comparando letras graças "strcmp" função da lib "string.h"
  int compara_letras(const void *m, const void *n)
  {
   char *m1 = (char *)m;
   char *n1 = (char *)n;
   return (strcmp(m1,n1));
  }
//comparando numeros
  int compara_numeros(const void *m, const void *n)
  {
   long *m1, *n1;
   m1 = (long *)m;
   n1 = (long *)n;
   return (*m1 > *n1);
  }

Outro exemplo arrays tridimensionais com ponteiros

/*
 *   Explanação arrays tridimensionais com Ponteiros
 *
 *
 *
 * c00f3r[at]gmail[dot]com
 * by Cooler_
 */
#include <stdio.h>
#include <stdlib.h>

int main()
{
/* array tridimensional
 *
 * [][][]
 * | | |_posição do caracter, todos caracter formam 1 palavra
 * | |___número da posição onde esta a palavra
 * |____ número da lista de palavras a usar
 *

 */
//  produto por 2 de char** pois vamos fazer 2 listas de palavras
 char ***lists=(char ***)malloc( 2*sizeof(char **)   );

//produto por 3 em char* pq vamos usar 3 palavras
 *(lists+0)=(char **)malloc(3*sizeof(char *));
// pode-se fazer tb lists[0][0]="ola"
 *(*(lists+0)+0)="ola";
 *(*(lists+0)+1)="Yay";
 *(*(lists+0)+2)="lol";
// adiciona mais um elemento caso queira
 lists[0][3]=(char *)realloc(lists[0],4*sizeof(char *));
 *(*(lists+0)+3)="iai";

 *(lists+1)=(char **)malloc(3*sizeof(char *));
 *(*(lists+1)+0)="epic";
 *(*(lists+1)+1)="let";
 *(*(lists+1)+2)="omg";

 fprintf(stdout," %s \n %s \n %c\n",lists[0][2],lists[1][0],lists[0][0][1]);
/* mostrando uma saida qualquer
 repare o terceiro elemento palavra "ola" segunda letra "l"

lists[0][0][1]='l'
            |
 [o][l][a] _|
  0  1  2
*/

// usar free() onde usou malloc() para liberar memória HEAP
 free(lists[0]);
 free(lists[1]);
 free(lists);

// caso use windows coloque um pause aqui no final 😉
 return 0;
}

Exemplo ,uma agenda simples usando struct com ponteiros

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// by Cooler agenda exemplo

//limite cadastros
#define LIMITE 1024 

#define BUFFER 32

//macro Anti Bug do "new line" comum em compiladores antigos, 1 para ativar 0 para desativar
#define ANTBUG 1

struct agenda  {
 char nome[BUFFER];
 int ra;
};

struct agenda list[LIMITE],carry;
struct agenda *lista=list;

int cmp(const void *a, const void *b)
{
//faz o casting para struct e verifica em ordem decrescente
 struct agenda *ia = (struct agenda *)a;
 struct agenda *ib = (struct agenda *)b;
 return (strcmp(ia->nome,ib->nome));
}

void banner()
{
 puts("\ncode agenda by cooler\n digite numero da opção\n 0- exit\n 1 inserir\n 2 remover \n 3 listar \n 4 listar em ordem de nome\n");
}

void inserir (int count)
{
 if(count != LIMITE)
 {
  puts("\ndigite nome");
  scanf("%30s",lista[count].nome);
#if ANTBUG
  getchar();
#endif
  puts("\ndigite RA");
  scanf("%6d",&lista[count].ra);
#if ANTBUG
  getchar();
#endif
 }
 else {
  puts("agenda cheia");
 }
}

void delete(int count)
{
 int position=0,count3=0,count2=0;

 puts("qual RA para remover cadastro ?\n");
 scanf("%6d",&position);
#if ANTBUG
  getchar();
#endif

 count3=count;

 while(count)
 {
   if(lista[count].ra == position)
   {
    count2=count;

    while(count2<count3)
    {
     carry=lista[count2];
     lista[count2]=lista[count2+1];
     lista[count2+1]=carry;
     count2++;
    }

    break;
   }
  count--;
 }

}

void listar(int count)
{
 while(count)
 {
  fprintf(stdout,"Nome: %s  RA: %d   position: %d\n",lista[count].nome,lista[count].ra,count);
  count--;
 }
}

int main()
{
 int escolha=1,count=0;

 while(escolha)
 {
  banner();
  scanf("%1d",&escolha);
#if ANTBUG
  getchar();
#endif
  switch(escolha)
  {
   case 1:
    count++;
    inserir(count);
   break;

   case 2:
    delete(count);
    count--;
    break;

   case 3:
    listar(count);
   break;

   case 4:
// quicksort para organizar por nome nossa lista
    qsort(lista,count+1,sizeof(struct agenda),cmp);
    listar(count);
   break;
  }
 }

 puts("saindo");

 return 0;
}

tem muitas dicas sobre o mesmo por ai, mas vou dar uma sugestão de leitura caso queira melhorar ainda mais em ponteiros famoso livro da truta 🙂
expert C

e também esse material de stanford,  espero ter ajudado 😉

Anúncios
 
5 Comentários

Publicado por em outubro 30, 2011 em Linguagem C

 

pkg-config informações sobre as bibliotecas

Bom dia Boa noite galera,tempinho ai que não mando algo paro blog,
mais aqui está um assunto interessante que muitos iniciantes ficam
perdidos em linguagem C, nada muito difícil algo bem sútil para
aprendizado.

Para instalar uma “API” para desenvolvimento em sistemas unix
á várias formas em Ruby por exemplo se usa gems,em Perl temos
o CPAN, Common Lisp temos asdf. E em C ? isso varia de distro
para distro pode-se usar apt-get,yum,pacman e os *BSD o ports
de acordo com o Sistema Operacional, entretanto todos tem o nome
do pacote semelhante na maioria das vezes podendo ter alguma
otimização ou versão mais atual dependendo se é current ,stable
em fim, por exemplo de pkg(pacote) vamos sitar uma API bem popular
a biblioteca do Curl ou seja libCurl, para poder usar temos que
instalar, podemos baixar o tarball extrair dar config,make,make install
ou podemos buscar nos repositórios exemplo se procurarmos “libcurl
não vamos encontrar um nome exato , você vai ver muitos tipos de
pacotes exemplo “libcurl-dev” que o “dev” significa development é
um pkg para desenvolvedor.

Outro argumento no final do pacote é o “doc” que significa
que é para documentação você vai poder usar o “man libcurl” por
exemplo,”dbg” pkg vem compilado com símbolos para depuração.

Algo bem interessante quando falamos de desenvolvimento em C
é saber onde está as APIs do sistema e detalhes claro que você
pode simplesmente abrir “/usr/include” e ver as headers a olho
nu , mais uma forma mais nobre de se informar é usar o
pkg-config“, exemplo

 $ pkg-config --list-all

uma lista das API instaladas irá surgir logo a frente informação
sobre as funções da mesma.

se quisermos saber se a libcurl foi instalada

 $ pkg-config --list-all | grep curl 

ver versão da header

 $ pkg-config --print-provides libcurl 

ver o último log da libcurl para depuração,algumas pkg pedem “*-dbg
no caso da libcurl não pede…

 $ pkg-config --debug libcurl | tail

exemplo referenciando as libs do GTK caso queira fazer uma aplicação
usando gtk,para não ter que escrever lib por lib com argumento “-l”

 $ gcc -o code code.c `pkg-config --cflags --libs gtk+-2.0` 

apenas mostrando a referencias das bibliotecas

 $ pkg-config --cflags gtk+-2.0

mais informações “man pkg-config

 
3 Comentários

Publicado por em outubro 27, 2011 em Linguagem C

 

C pitfalls

pitfall
Pitfall não é o GaMe HeHeHe 🙂

Quando falamos em “Pitfall“, falamos de uma analogia a armadilhas da
programação ou seja buracos , que quando se cai fica ruim de subir sem ajuda de
alguém , onde um programador iniciante pode errar e não conseguir ver onde está o erro.

Primeira dica use o argumento do GCC “-Wall” e “-Wextra“, vai te ajudar a ilustrar os erros mais comuns.

Segunda *Ler manuais para entender os protótipos isso ajuda
a entender melhor as funções, exemplo “man s snprintf”

Trap dos Sinais

*bom isso “==” é diferente disso “=”

“=” você usa para atribuição “x=2″,”if((Y=a+b)>X)”
“==” você usa para comparar se um valor for igual ao outro “if(x==y)”,”x=(a==b)?5:10;”

*isso “!=” é diferente disso ‘=!’
“!=” sinal de diferente para fazer comparação “if(x!=y)”
“=!” você seta uma var para NOT,if(x=(!y))

*confundir ponteiros com operador aritmético de produto “*”
invés de fazer x=2**pointer;
faça x=2*(*pointer);
isso evita comentários indesejados caso aja operador de divisão “/”

*esquecer de botar “;” no final de cada linha é um erro comum e fácil
de detectar

*setar errado variáveis na declaração pode dar dor de cabeça
invés de fazer “int x=3,y,z=1,c=314;”
faça “int x=3,z=1,c=314” e “int y” ou “int x,z,c,y” depois setar valores…
Exemplo comum de trap em chars

char letra = 'A';             // certo 
char letra = "A";             // errado   
const char * word = "A";     // certo
const char * word = 'A';     // errado

Problemas de Casting

*Erros de “Casting” tentar armazenar uma variável float
em Int sem converter ou Double invés de float…

5 exemplos de casting

//1
  int index = 1;
  float var = 0.0;
  index = (int)var;
//2
  char c = ’A’;   
  int x = (int)c;
//3
  int x;
//printando de "A" até "Z"
  for(x=97; x<=122; x++)
   printf(" %c ", (char)x);
//4
int x=7, y=5;
float z;
z = (float)x/(float)y;  
//5
int x = 13;
printf("x/2 is %f", (float)x / 2);

Problemas em Leituras de variáveis “STDIN”

Maioria do pessoal que começa em C comete este erro veja só
o exemplo do “scanf()”

 int x;
 char *palavra=malloc(8*sizeof(char));

 scanf("%d",&x);
// quando é string não usa "&"
 scanf("%s",&palavra);
 puts(palavra);
 printf("%d \n",x);
 free(palavra);

A o uso do operador “&” no “scanf()” quando trabalhamos com string
nos trás erro, outro problema comum é o bug do “newline”, ao teclarmos
“enter” no final de um “STDIN” no final da string fica “\n” alguns
casos ocorre um “jump” pelo código e alguns outros erros estranhos,
alguns usam “getchar()” para evitar, outros criam uma função ou macro

eu costumo usar ReadString, vou mostrar minha
macro e uma função do meu amigo m0nad

// minha macro para remover o '\n'
#define ReadString(a) fgets(a,sizeof(a),stdin),a[strlen(a)-1] = '\0'; 
 
//func fo m0nad
void
chomp (char * str)
{
  while (*str) {
    if (*str == '\n' || *str == '\r') {
      *str = 0;
      return;
    }
    str++;
  }
}

// ex de uso dump_line(stdin);
void dump_line( FILE * fp )
{
  int ch;
  while( (ch = fgetc(fp)) != EOF && ch != '\n' )
}

Sempre bom validar entradas “STDIN” para
ter um controle maior e melhorar segurança do seu programa, procurar usar
strncpy() invés de strcpy(), strncmp(),snprintf() e outras funções mais seguras, principalmente ao nidar com “argv” vide ataques de Buffer Overflow e format string.

*Pthread e o Lock com Mutex
Parece ser dica para ganhar desempenho , mais muitos acabam ganhando
dor de cabeça em não implementar , bom invés de

 pthread_mutex_lock(&count_lock); 
   temp = sqrt(x); 
   fd = open(fname, O_CREAT | O_RDWR, 0666); 
   count++; 
   *bufp = (char *)malloc(256); 
 pthread_mutex_unlock(&count_lock); 

faça

  temp = sqrt(x); 
  fd = open(fname, O_CREAT | O_RDWR, 0666); 
  pthread_mutex_lock(&count_lock); 
   count++; 
  pthread_mutex_unlock(&count_lock); 
  *bufp = (char *)malloc(256); 

trancar apenas o que for necessário, quando falamos de mutex

*Problemas na HEAP

Para evitar *Memory leaks sempre que usar a HEAP usar free(),
com “malloc()” dê “free(var)” para dar clear na HEAP, para verificar
se tem memory leaks no seu código use o valgrind.
Outra dica é usar alloca() já que é baseada em Stack invés de Heap,
mas tem um certo problema para depuração…
DMR ,Linus coment about alloca()

exemplo de uso do free()

#include <malloc.h>
#include <unistd.h>

int main()
{
 char *x=malloc(3*sizeof(char));

 x[0]='o';
 x[1]='l';
 x[2]='a';

 write(1,x,3);
 write(1,"\n",2);

 free(x);

 return 0;
}

Ao tirar o “free()” e passar o valgrind veja o que se passa

cooler@lisperian:~/c/pitfall$ valgrind ./a
==12647== Memcheck, a memory error detector
==12647== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==12647== Using Valgrind-3.6.1-Debian and LibVEX; rerun with -h for copyright info
==12647== Command: ./a
==12647==
ola
==12647==
==12647== HEAP SUMMARY:
==12647== in use at exit: 3 bytes in 1 blocks
==12647== total heap usage: 1 allocs, 0 frees, 3 bytes allocated
==12647==
==12647== LEAK SUMMARY:
==12647== definitely lost: 3 bytes in 1 blocks
==12647== indirectly lost: 0 bytes in 0 blocks
==12647== possibly lost: 0 bytes in 0 blocks
==12647== still reachable: 0 bytes in 0 blocks
==12647== suppressed: 0 bytes in 0 blocks
==12647== Rerun with --leak-check=full to see details of leaked memory
==12647==
==12647== For counts of detected and suppressed errors, rerun with: -v
==12647== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 11 from 6)

Veja que foi alocado e nada foi liberado na memória , use “free()”
caso não esteja convencido leia este paper da phrack clicando AQUI

O poderoso GDB

Quando você vê que nem você e nem seus amigos programadores acham o erro
então é hora de apelar para o GDB, sugestão para aprender usar GDB, paper
do mestre stallman

gnu gdb book

No desespero irc.freenode.net
canais #gdb,#c-br,#asm

espero ter ajudado 😉

 
2 Comentários

Publicado por em outubro 19, 2011 em Linguagem C, segurança de sistemas