Skip to content

Instantly share code, notes, and snippets.

@gustavoalbuquerquebr
Last active September 11, 2020 01:40
Show Gist options
  • Save gustavoalbuquerquebr/d464bb2d3a450838d15dd1e77a154fb1 to your computer and use it in GitHub Desktop.
Save gustavoalbuquerquebr/d464bb2d3a450838d15dd1e77a154fb1 to your computer and use it in GitHub Desktop.
#c

Basic structure

int main(void) {
  return 0;
}

Main's arguments

  • main's arguments are by convention called argc and argv (argument count, argument vector)
  • they are used to handle the arguments passed in the command line
  • argc is the number of arguments passed, including the program name
  • argv is a pointer array which points to each argument
  // print number or arguments, each one of them
int main(int argc, char *argv[] ) {
    printf("%i\n", argc);

    for(int i = 0; i < argc; i++) {
        printf("%s\n", argv[i]);
    }
}

Basics

read input

fgets

  • get a string from a stream (file or the standard input)
  • stops when the limit of chars was passed or when it finds a newline or end-of-file
  • fgets(myVar, 10, stdin);

scanf

NOTE: Avoid buffer overflow while using scanf to get a string, always limit the numbers of chars accepted

  • scanf(format, &variable) = reads data (of many formats, e.g. strings, numbers...) from the standard input
    • format = define width and accepted chars, e.g.
      • scanf("%10[A-z ]", myVar); max number of chars read is 10 and only accepts letters and space
      • scanf("%d", &myInt) will accept int numbers
    • variableAddress = the address of the variable to save the data (variable name preceded by '&')
      • strings don't need the ampersand, because in c, variables holding a string already are pointers pointing to the string's first char
  • multiple values input: scanf("%c %c", &x, &y); save first char in x and second in y

sizeof

  • sizeof(char) = returns the amount of memory that is allocated to the data type
    • you can use both with types sizeof(int) or expressions sizeof(3)
    • the parentheses are only required when used with types; e.g. sizeof "my string" is valid

constants

  • by convention, constants have capitalized names
  • two ways to declare a constant: define and const
    • #define VAL1 3
    • int const VAL2 = 5;

Pointers

  • pointer is a special type of variable whose value is the address of another variable

& and *

  • & = the address of
    • e.g.printf("%p\n", &x); => 0x7ffce383cd78
  • * = it'll be located in one of two places:
    • if in a variable declaration, make this variable a pointer to the variable in the right
      • e.g. int *y = &x; NOTE: (int specify that y will be a pointer to a variable of type int)
    • if in front of a already declared variable storing a pointer, go to the address that this pointer is pointing and get its value (dereferencing)
      • e.g. printf("%i\n", *y);

Strings

  • a string is a one-dimensional array of characters terminated by a null character \0
  • this null character is added automatically at the end of every sequence of characters enclosed with double quotes
  • the variable that holds a string is a pointer to the address of the string's first char

2 Methods to Create a string

1 - String as pointers

  • char *s = "abc";
    • allocates 4 consecutive bytes for a string literal ("abc\0")
    • and 8 extra bytes for the pointer (pointing to the address of the first char) that will be stored in the variable
    • can be entirely reassigned (x = "def"), that is, re-pointed to something else
    • but can't have its individual chars changed (x[0] = 'e')
    • no fixed length - you can reassigne to a smaller or bigger string

2 - String as arrays

  • char s[] = "abc"; length implicit, char s[] = "abc"; length explicit
    • creates a char array of 4 bytes ('a', 'b', 'c', '\0')
    • it'll have the same functionalities as a normal array
    • you can access a individual char (x[0])
    • can't be entirely reassigned (x = "def"),
    • but can have its individual chars changed (x[0] = 'e')
    • fixed length - you must say ahead of time how many characters the array may hold, this can't be change later

define a string type

  • you can create a custom string type to make variable creation easier
  • 1 - typedef char *string; = create type
  • 2 - string x = "test"; = declare variable with the new type

Variables types

  • strings must be declared with double quotes and chars with single quotes

NULL

  • NULL is limited to identifying a null pointer
#include <stdio.h>

int main(void) {
  int *p = NULL;

  if (!p) {
    printf("pointer is NULL");
  }
}

Type casting

Implicit

  • implicit casting happens when
    • operands have mismatched types,
    • or when you call a function using an argument whose type does not match the function’s corresponding parameter.
    • Programs also perform implicit type conversion as necessary when initializing variables or otherwise assigning values to them.

Explicit

  • (type) expression = explicit casting

Arrays

// you must declare which type the elements will be

// declare one by one
int x[5];
x[0] = 3;

// declare all at once
int x[5] = {3, 5, 8, 12, 15};

// pass arrays to functions (function declaration)
void test(int x[]);

arrays decays to a pointer when passed to a function

#include <stdio.h>

void myf(int arr[]);

int main(void) {
  int arr[] = { 3, 5, 8, 12, 15 };

  // array size is 20 and each element is 4 (because is an array of ints)
  printf("%lu, %lu\n", sizeof(arr), sizeof(arr[0]));
  myf(arr);
}

void myf(int arr[]) {
  // size is 8, because an array decays into a pointer to its first element
  // when it's passed to a function
  printf("%lu\n", sizeof(arr));
}

return array isn't possible, just return pointer

  • C programming does not allow to return an entire array
  • return a pointer instead
  • static is needed, otherwise the array values (after first one) will be lost
#include <stdio.h>

int *rarr();

int main(void) {
  int *p = rarr();

  // 'i < 3' because array is length 3
  for(int i = 0; i < 3; i++) {
    printf("%d\n", *(p + i)); // pointer arithmetic
  }
}

int *rarr() {
  // static is to preserve the variable even when out of their scope
  static int a[] = { 3, 5, 8 };
  return a;
}

pointer arithmetic

  • A pointer is a numeric value
  • do arithmetic operations with: ++, --, +, or -
  • each x increment/decrement, will skip x as many bytes as the type need (e.g. 4 for int)
  • array notation vs pointer arithmetic: ptr[x] is equivalent to *(ptr + x)

Functions

  • it's convention to let the 'main' function be on top
  • and declare only the other functions' prototypes (first line) before it
#include <stdio.h>

void test (void);

int main (void) {

    test();

}

void test (void) {
    printf("from test");
}

Structures

  • user defined data type used to group values of different types
  • it's convention to capitalize a struct name
  • struct myStruct x[5] = arrays w/ struct, the type of the array's elements will be the specified struct
  • void printBook( struct Books book ); = pass struct to functions
#include <stdio.h>
#include <string.h>

// declaration
struct Person {
  char name[10];
  int age;
};

int main(void) {
  // initialization
  struct Person person1;
  person1.age = 30;
  strcpy(person1.name, "John");

  // access
  printf("%s, %i\n", person1.name, person1.age);
}

typedef

  • typedef keyword creates an alias name for data types
  • used with structures to simplify the syntax of declaring variables
typedef struct Person {
  int age;
} person;

int main(void) {
  // declaration
  person me;
}

File I/O

  • fopen(filename, mode) = create a new file or open an existing file
    • mode = r (read), w (write), a (append), r+ (read and write), w+ ( read and write, trucantes file if already exists) and a+ (read and write, if file already exists write only can be appended).)
  • fclose(filePointer) = close a file and flushes any data still pending in the buffer;
  char fileContent[50];
  FILE *filePointer = fopen("log.txt", "a+");

  // read one line at time with fgets
  // fgets will store the content in the variable fileContent
  fgets(fileContent, 50, filePointer);
  printf("%s", fileContent);
  // after reading, fgets will move its internal pointer to the next line
  fgets(fileContent, 50, filePointer);
  printf("%s", fileContent);

  // write
  fprintf(filePointer, "log two\n");

  fclose(filePointer);

Libraries

string.h

strcpy

  • strcpy(dest, src);
  • make it easier to reassign a string declared with the bracket notation (char x[10]);

memcpy

  • memcpy(dest, src, bytesToCopy)
  // copy a string
  char *x = "test";
  char y[strlen(x)];
  memcpy(y, x, strlen(x));
  printf("%s\n", y);

  // copy a array
  int a[] = {3, 5, 8};
  int len = sizeof(a) / sizeof(a[0]);
  int b[len];
  memcpy(b, a, sizeof(a));

  for (int i = 0; i < len; i++) {
      printf("%i ", b[i]);
  }
  printf("\n");

Dynamic memory allocation

  • #include <stdlib.h> = to use any of the functions below, you need this include

access elements

  • two options to access elements in a space allocated with malloc, calloc, realloc:
    • by pointer arithmetic: *(ptr + x) = skips x times as many bytes as the type of element it points to
      • e.g. *(ptr + 0) points to the first element, *(ptr + 1) points to the second element and so on...
      • example: if a pointer contains the address of an integer, then adding one to that pointer means skipping 4 bytes to point to the next integer
  • by array notation: ptr[x] = equivalent to *(ptr + x); this is RECOMMENDED

malloc, pointer arithmetic

  • ptr = (cast-type*) malloc(byte-size) - memory allocation, dynamically allocate a single large block of memory with a specified size
    • returns a pointer, or NULL if the request fails
    • initializes each block with default garbage value
#include <stdio.h>
#include <stdlib.h>

int main(void) {
  int *ptr;
  int n = 3;

  ptr = (int*) malloc(sizeof(int) * n);

  if (ptr == NULL) {
    printf("Memory not allocated.\n"); 
    exit(0); 
  }

  // assign a value to each space
  for (int i = 0; i < n; i++) {
    ptr[i] = i * 2; // equivalent to *(ptr + i) = i * 2;
  }

  printf("%d in address %lu\n", ptr[0], ptr);
  printf("%d in address %lu\n", ptr[1], ptr + 1);
  printf("%d in address %lu\n", ptr[2], ptr + 2);

  free(ptr);
}

free

  • free(ptr) = frees the space allocated in the memory
    • its argument is the pointer returned by malloc, realloc, calloc...

calloc

  • ptr = (castType*) calloc(n, size); = contiguous allocation, almost the same as malloc, however there're 2 essential differences:
    • malloc leaves the memory uninitialized; calloc initialize all bits to zero
    • calloc takes two arguments: number of blocks and size of each block

realloc

  • ptr = realloc(ptr, newSize); = re-allocation; dynamically change the memory allocation of a previously memory allocated with malloc or calloc
    • maintains the already present value and new blocks will be initialized with default garbage value
#include <stdio.h>
#include <stdlib.h>

int main(void) {
  int *ptr;
  int n = 3;

  ptr = (int*) malloc(sizeof(int) * n);

  // assign a value to the first block
  // it'll be kept after realloc
  ptr[0] = 3;

  int newN = 5;
  ptr = (int*) realloc(ptr, newN);

  // assign a value to the new last block
  ptr[newN - 1] = 10;

  printf("%d in address %lu\n", ptr[0], ptr);
  printf("%d in address %lu\n", ptr[newN - 1], ptr + (newN - 1));
    
  free(ptr);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment