online compiler and debugger for c/c++

code. compile. run. debug. share.
Source Code   
Language
#include <stdio.h> #include "input.h" #include "password.h" // Programa "ScapeRoom" que conté errors intencionats. // L'objectiu de l'usuari és arreglar el codi per tal que funcioni bé. // Conté les explicacions suficients perquè tothom ho pugui resoldre (Després de // tot el codi) /** * Solucionat per Aleix Mariné-Tena * * Versió exhaustiva de la solució on s'intenten arreglar tots els errors, * es preveuen alguns casos extrems comuns en C al manipular input d'usuari i * s'apliquen algunes opinions en l'estil del codi. * * Canvis aplicats: * - Afegida llibreria per a llegir input d'usuari. L'error que soluciona es que * * 1.- scanf("%d", &pass); i similar es insegur per no especificar la mida * dels caràcters esperats, causant un possible stack overflow. * * 2.- La seva trucada té side-effects: Pot deixar caràcters al buffer que * entorpeixen lectures subseqüents i poden arribar a trencar l'execució. * * 3.- scanf("%s", nom); no controla correctament els espais, pel que dels * noms compostos només es llegiria el nom. * La llibreria internament fa servir fgets i controla errors típics de * caràcters vàlids, rangs, gestió del buffer d'input i casos extrems amb les * mides dels buffers. * - La mida dels buffers d'input passen a ser responsabilitat de la llibreria * d'input pel que s'omet la mida i es fan servir punters. * - Un password es redefineix com un string (char*) ja que el text lliure és el * tipus habitual per un password. En la mateixa linia, es fa servir strcmp * per a comprovar la seva correctesa. * - scanf("%d, nom); és obviament incorrecte i caldria llegir un string * - L'espai extra del scanf(" %c", &genere); és incorrecte i cal llegir només * un caràcter. * - Eliminat el cas else de la lectura de gènere ja que la funció de lectura * no continua amb la seva execució fins que no s'introdueixi un dels * caràcters acceptats. * - Canviat case 'X' del gènere incorrecte per 'N'. * - Truncades les línies de més de 80 caràcters, assumint que és aquest l'estil * del codi. * - Unificades la declaració de variables i s'alinien els comentaris. * - Es mou l'explicació a un fitxer independent de documentació * "explicació.md". * - Es canvia el password per un més adequat, es treu el password hard-coded * del codi i s'intercanvia per un fitxer de text amb el password en text clar * i una funció específica read_password_file() que el llegeix. * - Substituida la ç trencada del string pel seu equivalent unicode ja que no * es veia correctament al terminal del onlineGDB (ni probablement en cap * altre). * * Llibreria de la solució basada en la llibreria "libinput" de: * https://github.com/game-implementations/Battleship * * */ int main() { char *nom, // Variable per guardar el nom (cadena de caràcters) *pass, // Variable per comprovar la contrasenya genere; // Variable per guardar el gènere introduït // Missatge inicial de reptec printf("=============================================\n"); printf(" 🚀 BENVINGUT AL PRIMER REPTE DE CODE URV 🚀\n"); printf("=============================================\n\n"); printf("Seràs capac\u0327 d'arreglar el codi?\n"); printf("👉 Has d'aconseguir que el programa et doni la benvinguda\n"); printf(" personalitzada a l'associació.\n\n"); // Opció per demanar una pista printf("Vols una pista? Escriu la contrasenya (o 0 per continuar): "); pass = readString(); // Comprovar que la contrasenya és correcta char* password = read_password_file(); if (password != NULL) { if (strcmp(pass, password) == 0) { printf("\n🔑 PISTA: Revisa bé els formats de scanf, printf i les \ comparacions en el switch...\n\n"); } else if (strcmp(pass, "0") != 0) { printf("\n❌ Contrasenya incorrecta! Continua sense pista...\n\n"); } } else { printf("El programa no ha pogut llegir el fitxer de password, pel que\ no es pot comprovar."); } // Demanem el nom de l'usuari printf("Introdueix el teu nom: "); nom = readString(); // Demanem el gènere printf("Introdueix el teu gènere (M = masculí, F = femení, N = no binari):\ "); char valid_genres[] = {'M', 'F', 'N'}; genere = readCharInSet(valid_genres, 3); // Mostrem un missatge de benvinguda personalitzat amb switch-case switch (genere) { case 'P': printf("Benvingut a code URV, %s\n", nom); break; case 'O': printf("Benvinguda a code URV, %s\n", nom); break; case 'N': //🔑 PISTA ERROR INTENCIONAL: hauria de ser 'N' printf("Benvingud@ a code URV, %s\n", nom); break; } return 0; }
#include "input.h" void discard_rest_of_line(void) { int c; while ((c = fgetc(stdin)) != '\n' && c != EOF) {} } char readChar() { char* readInput = (char*) calloc(100, sizeof(char)); do { if (fgets(readInput, 100, stdin) == NULL) { continue; } } while (readInput[1] != '\n'); return readInput[0]; } bool isCharInSet(char letter, char* characterSet, int numCharacterSet) { for (int i = 0; i < numCharacterSet; i++) { if (characterSet[i] == letter) { return true; } } return false; } char readCharInSet(char* characterSet, int numCharacterSet) { char readCharacter; bool hasSetError = false; do { if (hasSetError) { printf("You have given a char out of range. Try again.\n"); } readCharacter = readChar(); hasSetError = !isCharInSet(readCharacter, characterSet, numCharacterSet); } while (hasSetError); return readCharacter; } char *readString(void) { char buf[READSTR_BUFSIZE]; for (;;) { if (fgets(buf, sizeof buf, stdin) == NULL) { // EOF or error — just keep waiting for valid input clearerr(stdin); continue; } // If no newline, input was too long — discard rest of the line size_t len = strlen(buf); if (len > 0 && buf[len - 1] != '\n') { discard_rest_of_line(); } else if (len > 0) { buf[len - 1] = '\0'; // strip newline } // Allocate and return char *result = (char *) malloc(strlen(buf) + 1); if (!result) { // If allocation fails, prompt again continue; } strcpy(result, buf); return result; } } void* memcpy(void* dest, const void* src, size_t n) { // Initialize pointers with implicit size of a byte char* src_byte = (char*) src; char* dest_byte = (char*) dest; for (unsigned int i = 0; i < n; i++) { dest_byte[i] = src_byte[i]; } return dest; }
#include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <limits.h> #include <errno.h> #include <ctype.h> #include <string.h> // Size of the buffer when reading input #define READINT_BUFSIZE 64 // plenty for any int (+ spaces, sign, newline) #define READSTR_BUFSIZE 256 // plenty for typical input /** * Flushes the stdin buffer . */ void discard_rest_of_line(void); /** * Reads a char from user. * * @return Read char. */ char readChar(); /** * Reads a char from user input in a given set. While the data introduced is not a char or is not in the set, tries * again. The set goes from the minimum char to the maximum char including both of them. The range uses the ASCII * code. * * @param characterSet Set of characters that we accept as valid. * @param numCharacterSet Number of characters in the accepted character set. * @return Read char. */ char readCharInSet(char* characterSet, int numCharacterSet); /** * Returns true if the supplied char is in the set, false otherwise. * * @param letter Character that we are querying. * @param characterSet Set of characters that we accept as valid. * @param numCharacterSet Number of characters in the set that we accept as valid. * @return True if the char is in the set, false otherwise. */ bool isCharInSet(char letter, char* characterSet, int numCharacterSet); /** * Reads a line from stdin, discards newline * and repeats until a non-empty string is read. * Always returns an allocated string (never NULL). * @return Pointer to a buffer containing the read string */ char *readString(void); /** * Copies n bytes from source to destination. * * @param dest Pointer to the destination the copy. * @param src Pointer to the source of the data to copy. * @param n Number of bytes to copy. * @return Destination address. */ void* memcpy(void* dest, const void* src, size_t n);
## EXPLICACIÓ: - `printf("text", variables...);` Serveix per mostrar text per pantalla. El text pot incloure "formats" especials: * `%s` = imprimir una cadena de caràcters (string) * `%c` = imprimir un caràcter * `%d` = imprimir un enter (int) - `scanf("format", &variable);` Serveix per llegir dades que l'usuari introdueix pel teclat. El "format" indica quin tipus de dada s’espera. És important passar l'**adreça** de la variable (amb `&`) per a que `scanf` hi pugui guardar el valor. **Exemple correcte per llegir un nom:** ```c scanf("%s", nom); // perquè "nom" és un array de chars
CODE URV MOLA
#include "password.h" char *read_password_file(void) { const char *filename = "PASSWORD"; FILE *fp = fopen(filename, "r"); if (!fp) { perror("Error opening PASSWORD file"); return NULL; } // Seek to the end to know the size if (fseek(fp, 0, SEEK_END) != 0) { perror("Error seeking file"); fclose(fp); return NULL; } long size = ftell(fp); if (size < 0) { perror("Error getting file size"); fclose(fp); return NULL; } rewind(fp); // Allocate buffer (+1 for null terminator) char *buffer = malloc(size + 1); if (!buffer) { perror("Memory allocation failed"); fclose(fp); return NULL; } size_t read_size = fread(buffer, 1, size, fp); buffer[read_size] = '\0'; // Null-terminate if (ferror(fp)) { perror("Error reading file"); free(buffer); fclose(fp); return NULL; } fclose(fp); return buffer; }
#include <stdio.h> #include <stdlib.h> char *read_password_file(void);

Compiling Program...

Command line arguments:
Standard Input: Interactive Console Text
×

                

                

Program is not being debugged. Click "Debug" button to start program in debug mode.

#FunctionFile:Line
VariableValue
RegisterValue
ExpressionValue