Important Details to Understand About C Language

Zouhair GrirZouhair Grir
4 min read
  1. multiple pointers can point on the same memory location

         #include <stdlib.h>
         int main(){
             int *pt1 = malloc(sizeof(int));
             if(pt1 == NULL){    return(1);    }
             *pt1 = 42;
             int *pt2 = pt1; // point pt2 to the same memory location as pt1
             int *pt3 = pt2;// point pt3 to the same memory location as pt2
             free(pt1);
                 return(0);
         }
    
  2. size_t is used because lengths can't be negative and it handles large memory efficiently.
    In General: For size-related tasks (like arrays and memory allocations), size_t is better due to its flexibility and portability.

         size_t ft_strlen(const char *s)
    
  3. C Language allows the char type to be either signed or unsigned, depending on the compailer and architecture that’s why should handle this case, that why we cast it to be unsigned char
    if char is signed can hold negative values (from -128 to 127), while an unsigned char holds values (from 0 to 255)

         #include <stdio.h>
         int main()
         {
             char normalChar = -1;
             printf("Normal char (as signed): %d\n", normalChar); // print : -1
    
             unsigned char unsignedChar = (unsigned char)normalChar;
             printf("Converted to unsigned char: %u\n", unsignedChar);// print : 255
             return 0;
         }
    
  4. the (char ) Cast is necessary because haystack is declared as const char (meaning a pointer to a constant character), But the fucntion returns a char (a pointer to a non-constant charactere), the Cast ensure the function returns the correct type (char *)

           char *ft_return_haystack(const char *haystack) {
               return ((char *)(haystack));
           }
    

    char ft_strchr(const char *s, int c) const char *s This ensures that the function can read the string but cannot change it.This is important, especially when working with string literals, which are stored in read-only memory.

     //without const
     char *str = "Hello, World!";  // String literals are stored in read-only memory
     char *result = ft_strchr(str, 'W');
    
     // Let's assume we mistakenly modify the string
     *result = 'Z';  // Changing 'W' to 'Z'
    

    In this case, the program might crash or behave unpredictably because you're attempting to write to a part of memory that is supposed to be read-only.

  5. the reason we use void *str is because the function is designed to work with any type of data.

           void *ft_return(void *str)
    

    unsigned char : converting the (void )pointer str to a pointer to unsigned char.

    This tells the compiler that str should now be treated as a pointer to a series of bytes (unsigned char),

    allowing you to manipulate the memory at the byte level.

           void *ft_return(void *str) {
               unsigned char *ptr;
               ptr = (unsigned char *)str;
               return ptr;
           }
    
  6. arrays in C are zero-indexed

  7. \==>Use + when converting an integer digit to its corresponding character.

     result += s[i]  '0';
    

    \==>Use - when converting a character back to its integer value

     result += s[i] - '0';
    
  8. When you allocate memory using malloc, you receive a pointer of type void *, which is a generic pointer type that can point to any data type. To use this pointer effectively, especially when you know the intended data type, you often cast it to the appropriate pointer type, such as char *, int *

     #include <stdlib.h>
     #include <stdio.h>
    
     int main() {
         char *s;
    
         // Allocate memory for 4 characters
         s = (char *)malloc(4 * sizeof(char));
    
         // Use the allocated memory (Example: store "abc" in the allocated memory)
         s[0] = 'a';
         s[1] = 'b';
         s[2] = 'c';
         s[3] = '\0';  // Null-terminating the string
    
         printf("The string is: %s\n", s);  // Output the string
    
         // Free the allocated memory when done
         free(s);
     }
    

    When you declare a variable like char P1;, you are creating a variable that holds a single character in stack memory. However, when you allocate memory using malloc, the memory allocated on the heap is indeed a pointer of type void *, which can be cast to any other pointer type.

  9. One of the key reasons to use malloc is dynamic memory allocation. By using malloc, you don't need to declare a fixed-size buffer in advance, and you can allocate exactly the amount of memory you need at runtime based on the input.

  10. you cannot dynamically allocate memory for char buffer[len]; like that in C unless len is a constant. This is because in C, arrays declared with the syntax char buffer[len]; are allocated on the stack, and the size must be known at compile time.

0
Subscribe to my newsletter

Read articles from Zouhair Grir directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Zouhair Grir
Zouhair Grir

I'm GRIR Zouhair, a dedicated and experienced Full-Stack Developer from Morocco. With a strong passion for coding and a knack for solving complex problems, I excel in creating robust and scalable web applications. My expertise spans across both front-end and back-end technologies, allowing me to deliver comprehensive and seamless solutions.