Etiquetas

C (31) Cpp (28) Linux (14) asm (8) Telegram (5) bot (5) libreria (5) Algoritmo (3) Errores comunes (3) python (3) Opengl (2) kali (2) Android (1) Snippet (1) nano (1) recursividad (1)

viernes, 31 de mayo de 2024

Los 11 fallos más comunes en Lenguaje C

(1)Mezclar enteros signed y unsigned.
(2)Sobrepasando límites de un arreglo.
(3)Perdiendo la condición base de una funcion recursiva.
(4)Usando constantes de caracteres en vez de literales de cadena y viceversa.
(5)Literales de tipo float son por defecto de tipo double.
(6)Olvidando liberar la memoria.
(7)Añadiendo un semicolon a #define.
(8)No ser cuidadoso con el semicolon.
(9)Erroneamente escribir = o ==.
(10)Copiando demasiado.
(11)Las macros son solo reeemplazo de cadenas.
1.- Mezclar enteros signed y unsigned en operaciones aritmeticas
#include stdio.h
int main(void){
unsigned int a = 1000;signed int b = -1;
if (a > b) puts("a is more than b");
else puts("a is less or equal than b");
return 0;}
Como 1000 es mayor que -1 uno esperaría que a es mayor que b. Antes de hacer la comparación, b es convertida a unsigned int. Cuando es convertido a unsigned int toma el valor máximo de unsigned int... el cual es mayor que 1000. Por esto se puede apreciar que a > b es una falso.
2.- Sobrepasando los límites de un arreglo.

Los arreglos siempre empiezan en 0 y terminan en la longitud del arreglo - 1.
#include stdio.h
int main(){
int x = 0;int myArray[5] = {1,2,3,4,5};
for(x=1; x<=5; x++){printf("%d\t",myArray[x]);}
printf("\n");return 0;} //Output: 2 3 4 5 GarbageValue
La forma correcta:
#include stdio.h
int main(){
int x = 0;int myArray[5] = {1,2,3,4,5};
for(x=0; x<5; x++){printf("%d\t",myArray[x]);}
printf("\n");return 0;} //Output: 1 2 3 4 5
Entonces, hay que conocer el límite de nuestros arreglos porque osino podemos corromper el buffer o provocar un fallo de segmentacion por acceder a un área de memoria distinta.
3.- Perdiendo la condición base en una función recursiva.
Calcular la factorización de un número es un ejemplo clásico de recursividad:
#include stdio.h
int factorial(int n){return n * factorial(n - 1);}

int main(){
printf("Factorial %d = %d\n", 3, factorial(3));return 0;}
//Typical output: Segmentation fault
El problema con esta función es que va a estar en un ciclo infinito, lo que causará fallo de segmentación. Necesita una condición base para detener la recursividad. La forma correcta:
#include stdio.h
int factorial(int n){
// Base Condition, very crucial in designing the recursive functions.
if (n == 1){return 1;}else{return n * factorial(n - 1);}}

int main(){
printf("Factorial %d = %d\n", 3, factorial(3));return 0;}
//Esta función va a terminar tan pronto alcance 1.
//Output : Factorial 3 = 6
Reglas a seguir:
1 Iniciar el algoritmo.
Las funciones recursivas necesitan con frecuencia un valor inicial con el que empezar. Esto es acompañado sea por un parametro de la función o una función puerta que no es recursiva pero pone los valores iniciales para la recursión.

2 Revisar para ver si los valores actuales que se están procesando coinciden con el caso base.Si es asi, entonces procesa y devuelve un valor


3 Redefine la respuesta en terminos de un problema pequeño o simple subproblema o subproblemas.

4 Ejecuta el algoritmo en un subproblema.
5 Combina los resultados en la formulación de la respuesta.
6 Retorna los resultados.

4.- Usando constantes de caracteres en vez de literales de cadena y viceversa.

En lenguaje C, las cadenas de caracteres y literales de cadena son cosas distintas. 'a' ..esto es una cadena de caracter. Una cadena de caracter es de tipo entero que tiene asignado un número para ese caracter. "asdf"... es un literal de caracteres. Un literal de caracteres un arreglo inmodificable cuyos elementos son de tipo char. "asdf" tiene 5 caracteres, porque el caracter final es un \0. Este caracter final es conocido como carácter nulo. {a,s,d,f,\0}.
//ejemplo 1: una cadena de caracteres es usada donde debería ir una literal de cadena. Esto da un comportamiento indefinido.
#include stdio.h
int main(void){
const char *hello = 'hello, world'; /* bad */puts(hello);return 0;}
//ejemplo 2:
un literal de cadena se usa donde se debería usar una cadena de caracteres. El resultado es una cosa sin sentido.
#include stdio.h
int main(void) { char c = "a"; /* bad */ printf("%c\n", c); return 0;}
En ambos casos el compilador se va a quejar de la mezcla. Si no pasa esto, necesita usar más advertencias para la compilación, o derechamente usar un mejor compilador.

5.- Literales de tipo float son por defecto de tipo double.

Hay que tener cuidado al inicializar una variable float a valores literales o compararlas con estos. Esto es debido a que literales float de valor 0.1 por lo regular son de tipo double. Este tipo de cosas nos puede conducir a sorpresas:

#include stdio.h

int main(){
float n = 0.1; if (n > 0.1) printf("Wierd\n");return 0;}
// Prints "Wierd" when n is float
n fue inicializada y redondeada por precisión, resultando en 0.10000000149011612. Entonces, n es vuelto a convertir en double para ser comparado con el valor literal 0.1 (lo cual es igual a 0.10000000000000001) lo que da una discordancia. Mezclar variables float con literales dobles puede resultar en pobre desempeño en plataformas donde no hay soporte de hardware para doble precisión.

6.- Olvidando liberar la memoria.

Uno siempre debe recordar liberar la memoria alojada, sea una función hecha por tí o por una función de librería llamada por tu función.
#include stdlib.h #include stdio.h

int main(void){
char *line = NULL;size_t size = 0;
/* memory implicitly allocated in getline */
getline(&line, &size, stdin);
/* uncomment the line below to correct the code */
/* free(line); */return 0;}
Es un error inocente en este ejemplo específico,porque cuando un proceso termina,la mayoría de los sistemas operativos libera la memoria alojada en vez de tí.
7.- Añadiendo un semicolon a #define

Muchas veces me pasó a mí!!! Es fácil confundirse con el preprocesador de C, y tratarlo como parte del lenguaje. Pero es un error, porque el preprocesador es sólo un mecanismo de reemplazo de texto.
// WRONG
#define MAX 100; int arr[MAX]={0};
//lo cual se traduce como
int arr[100]={0}; //Que se traduce como error de sintaxis.

8.- Ser cuidadoso con el semicolon
//Esto: if (x > a); a = x;
//Significa esto:
if (x > a) {} a = x;
Aveces, perder un semicolon puede provocar problemas inesperados:
if (i < 0) return day = date[0]; hour = date[1]; minute = date[2];
/*El semicolon antes de return está perdido, por lo que day =date[0]; va a ser regresado. El compilador lee hasta que encuentra ; como el fin de línea.*/

9.- Erroneamente escribir = en vez de ==.
El = es para asignar.
El == es para COMPARAR.
A veces hacemos:
/* assign y to x */ if (x = y) {/* logic */}
//cuando lo que uno queria era:
/* compare if x is equal to y */ if (x == y) {/* logic */}

//lo cual es equivalente a:
/* compare if x is equal to y */ if (x == y) != 0{/* logic */}

10.- Copiando demasiado.
char buf[8]={0}; /* tiny buffer, easy to overflow */
printf("What is your name?\n");
scanf("%s", buf); /* WRONG */
scanf("%7s", buf); /* RIGHT */
Si uno pone más caracteres que los requeridos por scanf, van a empezar a sobreescribirse zonas de memorias aledañas al buffer. Esto puede derivar en comportamiento indefinido. Los hackers maliciosos con frecuencia usan esto para sobreeescribir la dirección de return, y cambiar la dirección por la del código malicioso creado por este.
11.- Las Macros son solo reemplazo de cadenas
#include stdio.h
#define SQUARE(x) x*x
//este es el error.
int main(void){
printf("%d\n", SQUARE(1+2));return 0;}
Esperarías que este código devolviese 9, pero devolverá 5 porque la macro será expandida a 1+2*1+2. Para evadir este problema debe encerrar entre () las fichas para evadir este problema.
#include stdio.h
#define SQUARE(x) ((x)*(x))
int main(void){
printf("%d\n", SQUARE(1+2));return 0;}

TextView and EditText en Android

crear un archivo .xml con esto: LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> /LinearLayout> ........Encerrar LinearLayout entre <> (no me deja poner el código xml) y escribir esto en un archivo .xml: LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> /LinearLayout> TextView and EditText in Android

Diferencias entre const int y int const

Una respuesta simple: leer hacia atrás. Los punteros como sabréis son variables especiales que apuntan a otras variables, y las constantes son variables que no cambian durante la ejecución de un programa. int * ptr = ptr es un puntero hacia int. int const * ptr = ptr es un puntero hacia constante int. int * const ptr = ptr es un puntero constante hacia int. const int * const ptr = ptr es una constante puntero a una constante int. const int * ptr es igual a int const * ptr const int * const ptr es igual a int const * const ptr véase que lo que cambia es lo que esta antes de *ptr o *const ptr. int ** ptr = is a pointer to pointer(p2p) to int. Un puntero que apunta hacia otro puntero. int ** const ptr = ptr es un puntero constante de un puntero hacia int. int * const * ptr = ptr es un puntero a una constante puntero hacia int. int const **ptr = ptr es un puntero de un puntero hacia una constante int. int * const * const ptr = ptr es un puntero constante de otro puntero constante hacia int. ¿Como saber si const se refiere al puntero o lo apuntado? Si está del lado derecho del asterico, entonces se refiere a lo apuntado. Si está del lado izquierdo del asterico, del puntero. Fuente: What is the difference between const int and int const.

miércoles, 22 de mayo de 2024

Colores c.nanorc

## Syntax highlighting for C and C++ files. syntax c "\.([ch](pp|xx)?|C|cc|c\+\+|cu|H|hh|ii?)$" header "-\*-.*\" # Labels. color brightmagenta "^[[:blank:]]*[A-Z_a-z][0-9A-Z_a-z]*:[[:blank:]]*$" color normal ":[[:blank:]]*$" # Types and related keywords. color green "\<(auto|bool|char|const|double|enum|extern|float|inline|int|long|restrict|short|signed|sizeof|static|struct|typedef|union|unsigned|void)\>" color green "\<([[:lower:]][[:lower:]_]*|(u_?)?int(8|16|32|64))_t\>" color green "\<(_(Alignas|Alignof|Atomic|Bool|Complex|Generic|Imaginary|Noreturn|Static_assert|Thread_local))\>" color green "\<(class|explicit|friend|mutable|namespace|override|private|protected|public|register|template|this|typename|using|virtual|volatile)\>" # Flow control. color brightyellow "\<(if|else|for|while|do|switch|case|default)\>" color brightyellow "\<(try|throw|catch|operator|new|delete)\>" color magenta "\<(break|continue|goto|return)\>" # Single-quoted stuff (characters, backslash escapes, hex and octal byte codes). color brightmagenta "'([^'\]|\\(["'\abfnrtv]|x[[:xdigit:]]{1,2}|[0-3]?[0-7]{1,2}))'" # GCC builtins. color cyan "__attribute__[[:blank:]]*\(\([^)]*\)\)|__(aligned|asm|builtin|hidden|inline|packed|restrict|section|typeof|weak)__" # Strings and names of included files. color brightyellow ""([^"]|\\")*"|#[[:blank:]]*include[[:blank:]]*<[^>]+>" # Preprocessor directives. color brightcyan start="^[[:blank:]]*#[[:blank:]]*(if(n?def)?|elif|warning|error|pragma)\>" end="(\`|[^\])$" color brightcyan "^[[:blank:]]*#[[:blank:]]*((define|else|endif|include(_next)?|line|undef)\>|$)" # Comments. color brightblue "//.*" color brightblue start="/\*" end="\*/" # Reminders. color brightwhite,yellow "\<(FIXME|TODO|XXX)\>" # Trailing whitespace. color ,green "[[:space:]]+$"