LLuciano Posted August 10, 2024 at 11:36 AM Share Posted August 10, 2024 at 11:36 AM Fala pessoal.. Estava estudando C aqui e resolvi fazer um programinha de soma, bem simples.. eu passo no terminal o números e ele me devolve a soma. Dava para fazer tudo na main.. mas decidi criar uma função para o caso de animar a fazer outras operações além da soma e também treinar o uso de ponteiros.. ai que veio o problema. O programa está assim: #include<stdio.h> #include<string.h> #include<stdlib.h> int sum(int n, char **args[]); int main(int argc, char *argv[]) { if (argc < 3) { puts("usage: calc n1 n2"); exit(1); } int result; result = sum(argc, &argv); printf("%d\n", result); return 0; } int sum(int n, char **args[]) { int result = 0; for (int i = 1; i < n; i++) result += strtol((*args)[i], NULL, 10); return result; } O problema está na linha 26: result += strtol((*args)[i], NULL, 10); // aqui é versão que funciona Primeiro eu fiz o strtol sem o enclausurar o *args nos parênteses.. da seguinte forma: result += strtol(*args[i], NULL, 10); // versão com falha na segmentação. O Compilador aceitou, usei o GCC default para compilar.. porém em execução deu Segmentation fault: Program received signal SIGSEGV, Segmentation fault. 0x0000555555555201 in sum (n=4, args=0x7fffffffdfe0) at err-sum.c:26 26 result += strtol(*args[i], NULL, 10); Eu lembrei que para declarar uma ponteiro para função é necessário os parênteses devido a regra de precedência: int (*nome)(parametro1, ..) //ponteiro para função int * nome(parametro1, ..) // função que retorna um ponteiro para um inteiro. Então, por puro chute, eu resolvi colocar os parênteses e tudo funcionou lindamente… o problema é que não entendi o motivo que eu preciso usar esse parênteses ai. Na minha cabeça ao fazer *args[i] eu já estaria “desreferenciando” o suficiente. Alguém consegue me explicar? Tentei buscar nos materiais que eu tenho mas não consegui encontrar a explicação. Dá uma agonia qdo o negócio funciona e eu não entendo o movito.. kkkk Valeu Luciano. Ps: O nome mais esquisito esse de desreferenciar... Quote Link to comment Share on other sites More sharing options...
Administrators Fernando Mercês Posted August 10, 2024 at 03:00 PM Administrators Share Posted August 10, 2024 at 03:00 PM A explicação é complicada (para os meus parâmetros hehe), mas vou tentar. 🙂 *argv[] na main() já é um ponteiro para um array de chars. Mas é uma variável, e tem um endereço de memória (supomos, 0x200). Para a sum(), ao fazer &argv você passa o endereço de argv, ou seja, 0x200. Na sum() você recebe esse endereço como um ponteiro para ponteiro para um array de chars: **args[]. O que está certo. Na sum(), args contém um único elemento (o ponteiro para um array chars e não o array de chars em si). Com *args[i], sabendo que a precedência de [] é maior que a de *, então vamos analisar o loop: args[0] é o primeiro (e único) elemento de args. *args[0] o acessa. args[1] falha, pois args só contém um elemento. Segfault aqui. Agora, com (*args)[i]: (*args) é resolvido primeiro em todas as iterações do loop. O resultado é um ponteiro para um array de chars. (*args)[0] funciona, assim como (*args)[1], (*args)[2], até argc-1. Um desenho certamente explicaria melhor, ou talvez com o uso do GDB. Se não entender, avisa aí que eu tento de outra forma. Ou talvez outra pessoa explique melhor. 🙂 Em tempo, você complicou mais do que precisa. O que eu faria é: sum(int n, char *args[]) { // código strtol(args[i], ...); } main(int argc, char *argv[]) { // código sum(argc, argv); } Dessa forma você passa o argv, que já é um ponteiro para um array de char (C strings, neste caso) para sum() e ela acessa por args, que é do mesmo tipo. Outras ideias, só por curiosidade: Economizando a variável i ao somar do último para o primeiro elemento (ou seja, na ordem reversa): int sum(int n, char *args[]) { int result = 0; n--; while (n > 0) { result += strtol(args[n], NULL, 10); n--; } return result; } Economizando o uso de argc, já que o último elemento de argv é sempre nulo - ou seja, argv[argc] == NULL: int sum(char *args[]) { int result = 0; while (*args) { result += strtol(*args, NULL, 10); args++; } return result; } Ou uma versão menorzinha, aproveitando que ++ é um operador de pós-incremento (primeiro o valor é lido e depois é incrementado): int sum(char *args[]) { int result = 0; while (*args) result += strtol(*args++, NULL, 10); return result; } Mas aí já entram mais conceitos.. por exemplo *args é o mesmo que fazer *args != NULL. E args++ é aritmética de ponteiros. Não é "mais um" e sim "mais X bytes", onde X é o tamanho do tipo. Versão "olha mãe, sem as mãos": int sum(char *args[]) { return *args ? strtol(*args, NULL, 10) + sum(args + 1) : 0; } Aqui já entra recursividade (pode esgotar a pilha) e o ternário. Fiz essas coisas só para despertar a curiosidade mesmo e provar que C é a linguagem na qual o universo foi escrito. 😄 Abraço. 1 Quote Link to comment Share on other sites More sharing options...
LLuciano Posted August 10, 2024 at 06:00 PM Author Share Posted August 10, 2024 at 06:00 PM Nossa! Que aula! Valeu demais!! Em 10/08/2024 em 12:00, Fernando Mercês disse: 4 -Na sum(), args contém um único elemento (o ponteiro para um array chars e não o array de chars em si). Agora ficou tão óbvio!KKKK Acho que entendi perfeitamente sua explicação! Nada melhor do que tentar desenvolver do 0 minhas coisas.. eu sempre fiquei tentando resolver alguns exercícios que achava, mas no exercício já vem no meio do capítulo de um livro e ai a gente já vai achando as respostas e etc.. Em 10/08/2024 em 12:00, Fernando Mercês disse: int sum(char *args[]) { return *args ? strtol(*args, NULL, 10) + sum(args + 1) : 0; } Isso ficou demais! Um dia chego ai! Eu acho recursão o estado da arte na programação.. ainda não consegui desenvolver sozinho nenhuma função com recursão! Agora, colocar a recursão no meio de um ternário é pra emoldurar o código! Muito obrigado por responder! Forte Abraço! Luciano. 1 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.