├── .gitattributes ├── .gitignore ├── README.md └── utils ├── jco_list.c ├── jco_list.h ├── main.c └── makefile /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows thumbnail cache files 2 | Thumbs.db 3 | ehthumbs.db 4 | ehthumbs_vista.db 5 | 6 | # Folder config file 7 | Desktop.ini 8 | 9 | # Recycle Bin used on file shares 10 | $RECYCLE.BIN/ 11 | 12 | # Windows Installer files 13 | *.cab 14 | *.msi 15 | *.msm 16 | *.msp 17 | 18 | # Windows shortcuts 19 | *.lnk 20 | 21 | # ========================= 22 | # Operating System Files 23 | # ========================= 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Simple notes on the C Programming Language 2 | 3 | ## Description 4 | Some simple notes on the C programming language that I took while refreshing my C by reading books and online. Useful to me, hopefully useful to others. The two good books of C that I'm studying are:
5 | - C : A Software Engineering Approach, Third Ed. by Peter A. Darnell, Philip E. Margolis 6 | - C Programming : A modern Approach, Second Ed. by K. N. King 7 | 8 | ## Table of contents 9 | 10 | - [Simple notes on the C Programming Language](#simple-notes-on-the-c-programming-language) 11 | - [Description](#description) 12 | - [Table of contents](#table-of-contents) 13 | - [Names in C](#names-in-c) 14 | - [Function that exits a program - exit()](#function-that-exits-a-program---exit) 15 | - [printf and scanf](#printf-and-scanf) 16 | - [Scaler types](#scaler-types) 17 | - [TypeDef's](#typedefs) 18 | - [Pointers](#pointers) 19 | - [Multidimensional arrays](#multidimensional-arrays) 20 | - [True vs False](#true-vs-false) 21 | - [Switch](#switch) 22 | - [Logical operators](#logical-operators) 23 | - [Decrement and increment operators](#decrement-and-increment-operators) 24 | - [Comparing floating point values](#comparing-floating-point-values) 25 | - [Bit operators](#bit-operators) 26 | - [sizeof operator](#sizeof-operator) 27 | - [Structures](#structures) 28 | - [Structure operators](#structure-operators) 29 | - [Unions](#unions) 30 | - [Dynamic memory allocation on the Heap](#dynamic-memory-allocation-on-the-heap) 31 | - [Types of includes](#types-of-includes) 32 | - [Keyword static](#keyword-static) 33 | - [Same ways of defining strings](#same-ways-of-defining-strings) 34 | - [Functions for manipulating strings and general functions](#functions-for-manipulating-strings-and-general-functions) 35 | - [Functions for manipulating files](#functions-for-manipulating-files) 36 | - [Function pointers](#function-pointers) 37 | - [C99 - stdint.h - Primitive fixed size types](#c99---stdinth---primitive-fixed-size-types) 38 | - [Preprocessor Macros](#preprocessor-macros) 39 | - [Technique for defining more than one statement in a preprocessor Macro.](#technique-for-defining-more-than-one-statement-in-a-preprocessor-macro) 40 | - [C for Embedded Systems](#c-for-embedded-systems) 41 | - [Keyword **const** and **volatile**](#keyword-const-and-volatile) 42 | - [Sizes for 32 bit microController](#sizes-for-32-bit-microcontroller) 43 | - [Two ways of making a Menu with strings - char * - and send it to UART.](#two-ways-of-making-a-menu-with-strings---char----and-send-it-to-uart) 44 | - [Utils](#utils) 45 | - [Abstract Double Linked List - jco_list](#abstract-double-linked-list---jco_list) 46 | - [TODO:](#todo) 47 | - [Have fun!](#have-fun) 48 | 49 | 50 | ## Names in C 51 | 52 | 1. They are case sensitive. 53 | 54 | 2. They may start with a letter or a underscore "_". 55 | 56 | 3. Names can have only the following characters: underscores, letters or numbers. 57 | 58 | ## Function that exits a program - exit() 59 | 60 | ``` 61 | #include 62 | 63 | int main(void){ 64 | 65 | // Exit successfully. The program terminates at this point. 66 | exit(0); 67 | 68 | // Exit with error. 69 | exit(-1); 70 | } 71 | 72 | ``` 73 | 74 | ## printf and scanf 75 | 76 | ``` 77 | #include 78 | 79 | int main(void){ 80 | int num_1 = 1; 81 | int num_2 = 1; 82 | 83 | printf("The number %d + %d = %d", num_1, num_2, num_1 + num_2); 84 | 85 | // %d integer 86 | // %f floating point 87 | // %c char 88 | // %s NULL or '\0' terminated string 89 | // %x Hexadecimal number 90 | // %o Octal number 91 | 92 | int num_3; 93 | 94 | scanf("%d", &num_3); 95 | 96 | } 97 | 98 | ``` 99 | 100 | ## Scaler types 101 | 102 | 1. Primitive types. 103 | 104 | 2. Scientific notation. 105 | 106 | 3. Numerical constants 107 | 108 | 4. int vs float calculations 109 | 110 | 5. enum - enumeration types 111 | 112 | 6. C99 - bool - boolean type - stdbool.h 113 | 114 | ``` 115 | // ** 1 ** 116 | 117 | char 118 | short int 119 | int 120 | long int 121 | 122 | float 123 | double 124 | 125 | unsigned 126 | 127 | // example: 128 | unsigned int num_1 = 2; 129 | 130 | 131 | // ** 2 ** 132 | 133 | // Scientific notation 134 | float num_2 = 5e-5; 135 | double num_3 = 3.7e12; 136 | 137 | 138 | // ** 3 ** 139 | 140 | # define NUM_A 5.5 /* Double constant */ 141 | # define NUM_B 5.5f /* Float constant */ 142 | # define NUM_C 5.5e6L /* Long double constant */ 143 | 144 | # define ADDRESS 0x20004000UL /* Unsigned Long constant */ 145 | 146 | 147 | // ** 4 ** 148 | 149 | int i = 1; 150 | int j = 2; 151 | 152 | int k_1 = i/j; // Result 0 153 | 154 | float k_2 = i/j; // Result 0.0 155 | 156 | float k_3 = (float) i / j; // Result 0.5 157 | 158 | 159 | // ** 5 ** 160 | 161 | enum { red, green, blue } color; 162 | 163 | color = green; 164 | color = blue; 165 | 166 | // ** 6 ** 167 | 168 | // C99 - bool - boolean type - stdbool.h 169 | #include 170 | 171 | bool flag = false; 172 | flag = true; 173 | if (flag){ 174 | print("Flag is true!\n"); 175 | } 176 | 177 | 178 | // Data type 179 | void 180 | 181 | 182 | // Remainder % 183 | int x = 3; 184 | int y = 2; 185 | z = x % y; // Result z = 1 186 | 187 | ``` 188 | 189 | ## TypeDef's 190 | 191 | ``` 192 | // Defining a new type 1. 193 | typedef unsigned long int ULINT_T; 194 | 195 | ULINT_T var_A = 2; 196 | 197 | 198 | // Defining a new type 2. 199 | typedef char * PT_TO_CHAR_T; 200 | 201 | PT_TO_CHAR_T p1, p2; // This is equal to "char *p1, *p2;" 202 | 203 | 204 | // Defining a new type 3. 205 | typedef enum { 206 | red, 207 | green, 208 | blue 209 | } COLOR_T; 210 | 211 | COLOR_T my_color = green; 212 | 213 | ``` 214 | 215 | ## Pointers 216 | 217 | 1. The address of an object. 218 | 219 | 2. Initialization of pointer. 220 | 221 | 3. Dereferencing a pointer. 222 | 223 | 4. Pointer arithmetic. 224 | 225 | 5. Pointer subtraction. 226 | 227 | 6. NULL pointer. 228 | 229 | 7. Iterate until NULL pointer. 230 | 231 | 8. Passing pointers to functions arguments. 232 | 233 | 9. Accessing arrays with pointers. 234 | 235 | 10. Arrays of pointers. 236 | 237 | 11. Pointers to Pointers. 238 | 239 | ``` 240 | // ** 1 ** 241 | 242 | int j = 2; 243 | // The address of an object. 244 | &j 245 | 246 | 247 | // ** 2 ** 248 | 249 | // Pointer to int, initialized with the address of variable j. 250 | int *p1 = &j; 251 | 252 | 253 | // ** 3 ** 254 | 255 | // Dereferencing a pointer. The value pointed by the pointer. 256 | int k = *p1; 257 | 258 | 259 | // ** 4 ** 260 | 261 | // Pointer arithmetic. 262 | char * pC_1 = (char *) 0x02UL; 263 | char * pC_2; 264 | 265 | pC_2 = pC_1 - 1; // Address: 0x01 266 | pC_2 = pC_1 + 1; // Address: 0x03 267 | pC_2 = pC_1 + 2; // Address: 0x04 268 | 269 | 270 | int * pI_1 = (int *) 8UL; 271 | int * pI_2, * pI_3, * pI_4; 272 | 273 | pI_2 = pI_1 - 1; // Address: 4 Step 4 addresses bytes. 274 | pI_3 = pI_1 + 1; // Address: 12 Step 4 addresses bytes. 275 | pI_4 = pI_1 + 2; // Address: 16 Step 4 * 2 addresses bytes. 276 | 277 | 278 | // ** 5 ** 279 | 280 | // Pointer subtraction. 281 | int i = pI_4 - pI_2; // Result i = 3 282 | 283 | int i = pI_2 - pI_4; // Result i = -3 284 | 285 | 286 | // ** 6 ** 287 | 288 | // NULL pointer. 289 | int * pI_1 = 0; // The NULL pointer. 290 | int * pI_1 = NULL; // Also the NULL pointer. 291 | 292 | 293 | // ** 7 ** 294 | 295 | // Iterate until NULL pointer. 296 | 297 | char * p = "batatinhas"; 298 | 299 | while(p){ 300 | // Iterate until NULL pointer. 301 | } 302 | 303 | 304 | // ** 8 ** 305 | 306 | // Passing pointers to functions arguments. 307 | 308 | void clear(int * p){ 309 | *p = 0; 310 | } 311 | 312 | int main(void){ 313 | int ar_vars[2] = { 1, 2 }; 314 | clear(&ar_vars[1]); // Result ar_vars[2] = { 1, 0 } 315 | 316 | // We could also pass. 317 | clear(ar_vars); // that is the same of clear(&ar_vars[0]); Result ar_vars[2] = { 0, 0 } 318 | } 319 | 320 | 321 | // ** 9 ** 322 | 323 | // Accessing arrays with pointers. 324 | 325 | int ar_vars[4] = { 0, 1, 2, 3 }; 326 | 327 | // IMPORTANT: "ar_vars" is the same as "&ar_vars[0]" 328 | 329 | // IMPORTANT: "ar_vars[n]" is the same as "*(ar_vars + n)" and is the same as "*(p + n)" 330 | // if p is a pointer to the first position. 331 | 332 | 333 | // ** 10 ** 334 | 335 | // Arrays of pointers. 336 | int i, j, k = 1; 337 | 338 | int *p[]; 339 | 340 | p[0] = &i; 341 | p[1] = &j; 342 | p[2] = &k; 343 | 344 | int z = *p[0] + *p[1] + *p[2]; 345 | 346 | // Result z = 3 347 | 348 | 349 | // ** 11 ** 350 | 351 | // Pointers to Pointers 352 | 353 | // Fill with addresses. 354 | int j = 2; 355 | int *p_A = &j; 356 | int **p_B = &p_A; 357 | 358 | // Dereference the pointers. 359 | int x = *p_A; // Result x = 2 360 | 361 | int z = **p_B; // Result z = 2 362 | 363 | ``` 364 | 365 | ## Multidimensional arrays 366 | 367 | 1. Initialization 368 | 369 | 2. Passing arrays to functions. 370 | 371 | 3. To pass to a function an array with a single dimension. **IMPORTANT CASE** 372 | 373 | ``` 374 | // ** 1 ** 375 | 376 | int ar[4][3] = {{1, 2}, // Row x Column 377 | {3}, 378 | {4, 5}}; 379 | 380 | // Generates the following array: 381 | // 382 | // ar = 1 2 0 0 383 | // 3 0 0 0 384 | // 4 5 0 0 385 | // 0 0 0 0 386 | // 387 | // ar[2][1] --> value 5 Row 2 Column 1 388 | 389 | 390 | // ** 2 ** 391 | 392 | // Passing arrays to functions. 393 | // The array isn't copied only de reference is copied. 394 | 395 | int clear(int ar_tmp[][3], size_row, size_column, 396 | position_clear_x, position_clear_y){ 397 | ar_temp[position_clear_x][position_clear_y] = 0; 398 | } 399 | 400 | // To call the function do... 401 | 402 | clear(ar); 403 | 404 | // Other way of defining the function to pass an array using pointers would be... 405 | 406 | int clear(int **ar_tmp, size_row, size_column, position_clear_x, position_clear_y){ 407 | // but in here you would need to make some calculation for 408 | // the indexing of the using pointers and pointer arithmetic. 409 | 410 | } 411 | 412 | // ** 3 ** 413 | 414 | // To pass to a function an array with a single dimension. 415 | 416 | int clear(int ar_tmp[], size_row, position_clear){ 417 | ar_temp[position_clear] = 0; 418 | } 419 | 420 | clear(ar); 421 | 422 | // Or it could be done using pointers. 423 | 424 | int clear(int *ar_tmp, size_row, position_clear){ 425 | *(ar_temp + position_clear) = 0; 426 | } 427 | 428 | ``` 429 | 430 | ## True vs False 431 | 432 | 1. How logic works? 433 | 434 | 2. Ternary operator 435 | 436 | 3. Short circuit with operators 437 | 438 | ``` 439 | // ** 1 ** 440 | 441 | int num_k = 0; // 20 442 | 443 | if (num_k){ // This is (num_k != 0) True 444 | 445 | }else{ // This is (num_k == 0) False 446 | 447 | } 448 | 449 | 450 | // ** 2 ** 451 | 452 | // Ternary operator. 453 | int i = (2 > 1) ? 1 : 2; 454 | 455 | 456 | // ** 3 ** 457 | 458 | // Short circuit with operators. Those are valid. 459 | 460 | if (a && 1 / a){ 461 | 462 | } 463 | 464 | if (ptr && *ptr++){ 465 | 466 | } 467 | 468 | ``` 469 | 470 | ## Switch 471 | 472 | ``` 473 | int i = 20; 474 | int j; 475 | 476 | switch(i){ 477 | case 0: 478 | j = 0; 479 | break; 480 | case 1: 481 | j = 1; 482 | break; 483 | case 2: 484 | j = 2; 485 | break; 486 | default: 487 | printf("test"); 488 | break; 489 | } 490 | 491 | ``` 492 | 493 | ## Logical operators 494 | 495 | 1. && - AND 496 | 497 | 2. || - OR 498 | 499 | 3. ! - NOT 500 | 501 | ## Decrement and increment operators 502 | 503 | 1. ++a - increment a, then get value of a. Prefix. 504 | 505 | 2. a++ - get value of a, then increment a. Posfix. 506 | 507 | ## Comparing floating point values 508 | 509 | 1. Never compare with equals "==". 510 | 511 | ``` 512 | float x = 2.0; 513 | 514 | if ( (x > 2.0 - 0.0001) && (x < 2.0 + 0.0001){ 515 | 516 | // Inside the tolerance interval. 517 | // Always compare with interval, never with exact values, 518 | // because floating point representation may not have exact values. 519 | 520 | } 521 | 522 | ``` 523 | 524 | ## Bit operators 525 | 526 | ``` 527 | >> - Right shift 528 | << - Left shift 529 | & - Bitwise AND 530 | | - Bitwise OR 531 | ^ - Bitwise XOR 532 | ~ - Bitwise complement 533 | 534 | ``` 535 | 536 | 537 | ```C 538 | 539 | // REG_A - Is a example Micro-controller peripheral register, 540 | // that is memory mapped into a memory address. 541 | // They can be found in the datasheet of the MCU, 542 | // in the section of the registers of the specific 543 | // peripheral and there, you can find also the info 544 | // on the functionality of every bit in it. 545 | // Some register are Write only, some are Read only, 546 | // some of them are Read and Write. 547 | // The Datasheet, User Guide and Erratas of them 548 | // for the MCU are the truth that will guide you! 549 | 550 | 551 | // SET BIT - Set Bit 2 to 1 (True) on REG_A with OR: 552 | REG_A |= (1 << 2); 553 | 554 | // Set bit 2 and bit 4 to 1 (True): 555 | REG_A |= ( (1 << 2) | (1 << 4) ); 556 | 557 | 558 | // CLEAR BIT - Clear Bit 2 to 0 (False) on REG_A with AND and NOT: 559 | REG_A &= ~(1 << 2); 560 | 561 | // Clear bit 2 and bit 4 to 0 (False): 562 | REG_A &= ~( (1 << 2) | (1 << 4) ); 563 | 564 | 565 | // TOGGLE BIT - Toggle or flip bit 2 on REG_A with XOR: 566 | REG_A ^= (1 << 2); 567 | 568 | // Flip bit 2 and bit 4 from 0 -> 1 or from 1 -> 0: 569 | REG_A ^= ( (1 << 2) | (1 << 4) ); 570 | 571 | 572 | 573 | // Make a one bit light up from right to left and from left to right: 574 | 575 | #define DELAY_TIME 300 /* ms */ 576 | 577 | // PORTB is a 8 bit ports. 578 | REG_A = 0; // Clears REG_A. 579 | uint8_t i; 580 | 581 | // From right to left. 582 | for(i=0; i < 8; i++) { 583 | REG_A |= (1 << i); // Set bit. 584 | _delay_ms(DELAY_TIME); 585 | REG_A &= ~(1 << i); // Clear bit. 586 | } 587 | 588 | // From left to right. 589 | for(i=7; i < 255; i--) { 590 | REG_A |= (1 << i); // Set bit. 591 | _delay_ms(DELAY_TIME); 592 | REG_A &= ~(1 << i); // Clear bit. 593 | } 594 | 595 | // Note: In the place of i < 255, 596 | // can't use i < 0 neither i <= 0. 597 | // The last one will give you 598 | // a infinite loop because of underflow. 599 | 600 | 601 | //###### 602 | // How to test if the bit of register is set to 1 or 0? 603 | 604 | // Test if the 2 bit is 1 (True). 605 | 606 | // REG_A : xxxx xxxx 607 | // (1 << 2): 0000 0100 608 | // & : 0000 0x00 609 | 610 | // In C, "if" is FALSE if is zero 611 | // and TRUE for all other values. 612 | 613 | if ( REG_A & ( 1<<2 ) ) { 614 | do_something(); 615 | } 616 | 617 | 618 | #define BIT_SHIFT(bit) ( 1 << (bit) ) 619 | #define BIT_IS_SET(reg, bit) ( (reg) & BIT_SHIFT(bit) ) 620 | #define BIT_IS_CLEAR(reg, bit) ( !( (reg) & BIT_SHIFT(bit) ) ) 621 | #define LOOP_UNTIL_BIT_IS_SET(reg, bit) do { } while ( BIT_IS_CLEAR(reg, bit) ) 622 | #define LOOP_UNTIL_BIT_IS_CLEAR(reg, bit) do { } while ( BIT_IS_SET(reg, bit) ) 623 | 624 | if (BIT_IS_SET(REG_A, 2)) { 625 | do_something(); 626 | } 627 | 628 | 629 | // ###### 630 | // To set a number or bit mask, 631 | // by clear the first 4 bit's 632 | // and set the first 2 bit's to 633 | // the number 3 (0000 0011) do: 634 | 635 | #define PC3 0x3 // 0000 0011 636 | 637 | REG_A = REG_A & 0b11110000; // clear all 4 bits 638 | REG_A = REG_A | PC3; // set the bits we need 639 | 640 | // More compact ways of doing it. 641 | 642 | REG_A = (0b11110000 & REG_A) | PC3; 643 | 644 | // or 645 | 646 | REG_A = (0xf0 & REG_A) | PC3; 647 | 648 | // or 649 | 650 | REG_A = (0xf0 & REG_A) | 3; 651 | 652 | 653 | // Important Note: 654 | // The bit manipulation notes are modified 655 | // versions from the fantastic book: 656 | // 657 | // Make: AVR Programming by Elliot Williams 658 | // 659 | // A can't recommend enough this book to all future embedded 660 | // or micro-controller developers because it's a really 661 | // important stepping stone in your journey 662 | // for every kind, brand and family of MCU not 663 | // just AVR. This book is that good! 664 | // 665 | // With it, you will learn 6 things, principles: 666 | // 1. - How to program a MCU just from registers. 667 | // 2. - How to read and use a MCU datasheet. 668 | // 3. - How to the set of most common MCU peripherals work 669 | // and how to use them well. 670 | // 4. - Bit fiddling and how to use timers and interrupts well. 671 | // 5. - Good practices of MCU development 672 | // and advanced stuff like ADC's, SPI, I2C, clocks and more. 673 | // 6. - Some really cool projects. 674 | // 675 | // Final note: This book is a labour of love 676 | // and you can see it in every word of it! 677 | // Make yourself a favour and grab a copy of it! 678 | 679 | 680 | 681 | 682 | // Simple debounce routine: 683 | 684 | #define DEBOUNCE_TIME 1000 /* ms */ 685 | #define BUTTON_PIN_A 1 686 | 687 | uint8_t debounce_button_A() { 688 | if ( BIT_IS_CLEAR( BUTTON_PIN_PORT_REG, BUTTON_PIN_A ) ) { 689 | // The button has a pull-up resistor 690 | // so it's active low, and we test if it is zero, 691 | // here it is pressed. 692 | _delay_us( DEBOUNCE_TIME ); 693 | if ( BIT_IS_CLEAR( BUTTON_PIN_PORT_REG, BUTTON_PIN_A ) ) { 694 | // We wait 1 ms and see if it is still pressed, 695 | // after the elapsed time and we return the state 696 | // of the button. 697 | return(1); 698 | } 699 | } 700 | return(0); 701 | } 702 | 703 | 704 | // To use do: 705 | 706 | if (debounce_button_A()) { 707 | do_something(); 708 | } 709 | 710 | 711 | ``` 712 | 713 | ## sizeof operator 714 | 715 | ``` 716 | sizeof(char); // 1 bytes 717 | sizeof(int); // 4 bytes - Value depends on the CPU architecture and compiler. 718 | sizeof(int *); // 8 bytes - For a 64 bits CPU 719 | 720 | int ar_var[2] = { 0, 1 }; 721 | 722 | sizeof(ar_var); // 8 bytes - Value depends on the CPU architecture, 723 | // compiler and memory alignment. 724 | 725 | // Number of elements of the array. 726 | int num_elems = sizeof(ar_var) / sizeof(ar_var[0]) ; // 2 elements 727 | 728 | ``` 729 | 730 | ## Structures 731 | 732 | 1. Definition of a structure and declaration of a variable. 733 | 734 | 2. Definition of a structure and declaration of a variable locally. 735 | 736 | 3. Definition of a new type with typedef of a structure. (This is the preferential way of declaring, that can easily be reused if made inside a '.h' file). 737 | 738 | 4. Initialization of a structure. 739 | 740 | 5. Iterating trough a structure array in a fast way inside a function. ** IMPORTANT CASE** 741 | 742 | 6. Nested structures, with and without typedef's. 743 | 744 | 7. Self referencing structures. 745 | 746 | 8. Bit Fields 747 | 748 | 9. Passing structures to functions. Pass by value or pass by reference. 749 | 750 | 10. Returning a structure from a function. By value and by reference. 751 | 752 | ``` 753 | // ** 1 ** 754 | 755 | // Definition of a structure. 756 | struct car{ 757 | char brandName[]; 758 | char *model; 759 | int numDoors; 760 | }; 761 | 762 | // Declaration of the variable of the structure. 763 | struct car mycar; 764 | 765 | 766 | // ** 2 ** 767 | 768 | // Definition of a structure. 769 | struct car{ 770 | char brandName[]; 771 | char *model; 772 | int numDoors; 773 | } cs, cs_ar[10], *pcs; 774 | 775 | // cs.numDoors - Variable car structure. 776 | 777 | // cs_ar[1].numDoors - Variable array of car structures. 778 | 779 | // (* pcs).numDoors <=> pcs->numDoors - Pointer do structure of car. 780 | 781 | 782 | // ** 3 ** 783 | 784 | // Definition of a new type with typedef of a structure. 785 | typedef struct { 786 | char brandName[]; 787 | char *model; 788 | int numDoors; 789 | } CAR; 790 | 791 | // Declaration of the variable of the structure. 792 | CAR myCar; 793 | CAR myCar[10]; 794 | CAR *pCar; 795 | 796 | // ** 4 ** 797 | 798 | // Initialization of a structure. 799 | myCar = { "Suzuki", "Cleo", 5 }; 800 | 801 | 802 | // ** 5 ** 803 | 804 | // Iterating trough a structure array in a fast way. 805 | 806 | // file 'car.h' 807 | 808 | #ifndef CAR_H 809 | #define CAR_H 810 | 811 | // Contains the definition of the new type car that is a structure. 812 | typedef struct { 813 | char brandName[]; 814 | char *model; 815 | int numDoors; 816 | } CAR; 817 | 818 | #endif 819 | 820 | // file 'car.c' 821 | 822 | #include "car.h" 823 | 824 | CAR all_cars[10]; 825 | 826 | int isThereACarWithNumOfDoors(CAR car_s[], int size, int numDoors){ 827 | CAR *pCar; 828 | CAR *pLastPlusOne = &car[size]: 829 | for(pCar = car_s; pcar < pLastPlusOne; ++p){ 830 | if (pCar->numDoors == numDoors){ 831 | return 1; // break and continue 832 | } 833 | } 834 | return 0; 835 | } 836 | 837 | int exists = isThereACarWithNumOfDoors(all_cars, 10, 4); 838 | 839 | 840 | // ** 6 ** 841 | 842 | // Nested structures. 843 | 844 | // With struct and variable declaration. 845 | struct car{ 846 | char brandName[]; 847 | int numDoors; 848 | struct { 849 | uint8_t day; 850 | uint8_t month; 851 | uint16_t year; 852 | } license_plate_date; 853 | }; 854 | 855 | // Variable of struct declaration and accessing the nested members of 856 | // the nested structure. 857 | car car_s; 858 | car_s.license_plate_date.day = 1; 859 | 860 | 861 | // With TypeDef. 862 | typedef struct{ 863 | uint8_t day; 864 | uint8_t month; 865 | uint16_t year; 866 | } DATE_T; 867 | 868 | 869 | typedef struct{ 870 | char brandName[]; 871 | int numDoors; 872 | DATE license_plate_date; 873 | } CAR_T; 874 | 875 | CAR_T car_s; 876 | CAR_T *pCar_s; 877 | 878 | // Accessing the nested structure member. 879 | car_s.license_plate_date.day = 1; 880 | pCar_s->license_plate_date.day = 1; 881 | 882 | // ** 7 ** 883 | 884 | // Self referencing structures. 885 | 886 | // IMPORTANT NOTE: You can only do self referencing structures 887 | // with struct and not with typedef. 888 | // But you can use typedef in the following way. 889 | // The reasons because struct permits self referencing structures 890 | // is because you can create a pointer to a type that doesn't exists 891 | // yet, this is called "forward referencing"and in a typedef that 892 | // isn't permitted. 893 | 894 | struct node{ 895 | int val; 896 | struct node *pNext; 897 | }; 898 | 899 | typedef struct node NODE_T; 900 | 901 | // Other way of doing the typedef, would be... 902 | 903 | typedef struct node{ 904 | int val; 905 | struct node *pNext; 906 | } NODE_T; 907 | 908 | // Or you can also have two structures referencing each other. 909 | 910 | struct node_A{ 911 | int val; 912 | struct node_B *pNext_node_B; 913 | }; 914 | 915 | struct node_B{ 916 | int val; 917 | struct node_A *pNext_node_A; 918 | }; 919 | 920 | typedef struct node_A NODE_A_T; 921 | typedef struct node_B NODE_B_T; 922 | 923 | // Personal note: See this with more attention regarding the typedef's. 924 | 925 | 926 | // ** 8 ** 927 | 928 | // Bit Fields 929 | 930 | struct date{ 931 | uint32_t day:5; 932 | uint32_t month:4; 933 | uint32_t year:11; 934 | } 935 | 936 | typedef struct date DATE_T; 937 | 938 | 939 | // ** 9 ** 940 | 941 | // Passing structures to functions. 942 | // Pass by value or pass by reference. 943 | 944 | // If you pass by value all the structure bytes have to be copied, 945 | // if you pass by reference only the 4 bytes of a pointer in 946 | // a 32 bits architecture, or the 8 bytes of a 64 bit architecture 947 | // have to be copied to the function parameters. 948 | // 949 | // NOTE: In this regard, it's different that for array's because 950 | // arrays are always passed by reference, coping of the address. 951 | 952 | 953 | struct tag{ 954 | int val_1; 955 | int val_2; 956 | } 957 | 958 | struct tag var_A; 959 | 960 | 961 | // By value ... 962 | 963 | void func_1(struct tag s1){ 964 | s1.val_1 = .... ; 965 | } 966 | 967 | // call passing all the structure. 968 | func1(var_A); 969 | 970 | 971 | // By reference ... 972 | 973 | void func_1(struct tag * pS1){ 974 | pS1->val_1 = .... ; 975 | } 976 | 977 | // call passing the address. 978 | func1( &var_A ); 979 | 980 | 981 | // IMPORTANT NOTE: The same can be made with typedef's.... 982 | 983 | typedef struct{ 984 | int val_1; 985 | int val_2; 986 | } TAG_T; 987 | 988 | void func_1(TAG_T s1){ 989 | s1.val_1 = .... ; 990 | } 991 | 992 | // or... 993 | 994 | void func_1(TAG_T * pS1){ 995 | pS1->val_1 = .... ; 996 | } 997 | 998 | 999 | // ** 10 ** 1000 | 1001 | // Returning a structure from a function. By value and by reference. 1002 | 1003 | typedef struct{ 1004 | int val_1; 1005 | int val_2; 1006 | } RET_VAL_T; 1007 | 1008 | 1009 | // By value ... 1010 | 1011 | RET_VAL_T calc_A(){ 1012 | RET_VAL_T ret; 1013 | ret.val_1 = 1; 1014 | ret.val_2 = 2; 1015 | return ret; 1016 | } 1017 | 1018 | RET_VAL_T temp = calc_A(); 1019 | 1020 | 1021 | // By reference ... 1022 | 1023 | RET_VAL_T * calc_B(){ 1024 | static RET_VAL_T ret; 1025 | ret.val_1 = 1; 1026 | ret.val_2 = 2; 1027 | return &ret; 1028 | } 1029 | 1030 | RET_VAL_T pTemp = calc_B(); 1031 | 1032 | 1033 | //****** 1034 | // The same can be made with struct not using typedef's. 1035 | 1036 | struct ret_val{ 1037 | int val_1; 1038 | int val_2; 1039 | }; 1040 | 1041 | 1042 | struct ret_val calc_A(){ 1043 | struct ret_val ret; 1044 | ret.val_1 = 1; 1045 | ret.val_2 = 2; 1046 | return ret; 1047 | } 1048 | 1049 | struct ret_val temp = calc_A(); 1050 | 1051 | 1052 | // By reference ... 1053 | 1054 | struct ret_val * calc_B(){ 1055 | static struct ret_val ret; 1056 | ret.val_1 = 1; 1057 | ret.val_2 = 2; 1058 | return &ret; 1059 | } 1060 | 1061 | struct ret_val pTemp = calc_B(); 1062 | 1063 | ``` 1064 | 1065 | ## Structure operators 1066 | 1067 | ``` 1068 | int j = x.y; // Get the value of member y in structure x. 1069 | 1070 | int j = p->y; // Get the value of member y in structure pointed to by p. 1071 | 1072 | // p->y <=> (*p).y - They represent the same thing. 1073 | 1074 | ``` 1075 | 1076 | ## Unions 1077 | 1078 | ``` 1079 | typedef union{ 1080 | struct{ 1081 | int a1; 1082 | int a2; 1083 | } s; 1084 | float j; 1085 | double k; 1086 | } UNION_NUM; 1087 | 1088 | UNION_NUM value; 1089 | 1090 | value.s.a1 = 1; // Only one of those values exists in memory 1091 | value.j = 4; // at the same time. 1092 | value.k = 8; 1093 | 1094 | ``` 1095 | 1096 | ## Dynamic memory allocation on the Heap 1097 | 1098 | 1. malloc() - Allocates one block of memory with a specific size, and returns a pointer to the first address of the block. 1099 | 2. calloc() - Allocates one or more memory blocks and initializes them to 0 (zero). 1100 | 3. realloc() - Allows you to change the size of a previous allocated memory block. 1101 | 4. free() - Free the memory allocated by a previous malloc(), calloc() or realloc(). 1102 | 1103 | ``` 1104 | // ** 1 ** 1105 | 1106 | // malloc - Allocates a memory block for 100 int's. 1107 | int * ptr_1 = (int *) malloc(100 * sizeof(int)) 1108 | if (ptt_1 == NULL) 1109 | printf("Error in malloc()."); 1110 | 1111 | 1112 | // ** 2 ** 1113 | 1114 | // calloc - Allocates a memory block for 100 int's. 1115 | int * ptr_2 = (int *) calloc(100, sizeof(int)); 1116 | if (ptt_1 == NULL) 1117 | printf("Error in calloc()."); 1118 | 1119 | 1120 | // ** 3 ** 1121 | 1122 | // realloc - Reallocates memory of a new size, the new size is not initialized. 1123 | unsigned int newSize = 200; 1124 | int * ptr_3 = realloc(ptr_1, newSize); 1125 | if (ptt_1 == NULL) 1126 | printf("Error in realloc()."); 1127 | 1128 | 1129 | // ** 4 ** 1130 | 1131 | // free - Free's the memory previously allocated. 1132 | free(ptr); 1133 | 1134 | ``` 1135 | 1136 | ## Types of includes 1137 | 1138 | ``` 1139 | // The include between < > is a standard C include, searched in the 'system' directory. 1140 | #include 1141 | 1142 | // The include between " " is a C include from my program, searched in the programs directory or similar. 1143 | #include "main.h" 1144 | 1145 | ``` 1146 | 1147 | ## Keyword static 1148 | 1149 | 1. In a file, outside of a function means that the variable scope is only the file, it's only visible in the file. Used to restrict access to the variable from outside of the file. 1150 | 1151 | 2. Inside a function, means that the variable is created in the first call to the function and it exists and maintains and can update the value in subsequent calls of the function. 1152 | 1153 | ## Same ways of defining strings 1154 | 1155 | 1. char message_1 [] - Array of chars. 1156 | 1157 | 2. char * message_2 - Pointer to chars. 1158 | 1159 | 3. uint8_t * message_3 - Pointer to uint8_t, equivalent to char. 1160 | 1161 | ``` 1162 | // ** 1 ** 1163 | 1164 | // A array of char's, '\0' terminated, but it doesn't have to be '\0' terminated. 1165 | char message_1[] = {'b','a','t','a','t','i','n','h','a','s','\n', '\0'}; 1166 | 1167 | // Also valid - '\0' terminated string. 1168 | char message_1[] = "batatinhas\n"; 1169 | 1170 | // The address of the first position of the array. 1171 | message_1 1172 | 1173 | // The first character, the character 'b'. 1174 | message_1[0] 1175 | 1176 | // The address of the second character, the address of character 'a'. 1177 | &message_1[1] 1178 | 1179 | // Attribution of a string to an char array. ILLEGAL 1180 | message_1 = "ERROR\n"; 1181 | 1182 | 1183 | // ** 2 ** 1184 | 1185 | // It places the '\0' automatically. 1186 | char * message_2 = "cemelhas\n"; 1187 | 1188 | // The address of the first character of the '\0' terminated string. 1189 | message_2 1190 | 1191 | // The first character 'c' of the '\0' terminated string. 1192 | *message_2 1193 | 1194 | // The third character 'm' of the '\0' terminated string. 1195 | *(message_2 + 2) 1196 | 1197 | // Attribution of character 'p' to the third character. 1198 | *(message_2 + 2) = 'p'; 1199 | 1200 | // Makes the pointer char *, point to the array of characters, the inverse isn't valid. 1201 | message_2 = message_1; 1202 | 1203 | 1204 | // ** 3 ** 1205 | 1206 | // It places the '\0' automatically. 1207 | uint8_t * message_3 = "cemelhas_2\n"; 1208 | 1209 | ``` 1210 | 1211 | ## Functions for manipulating strings and general functions 1212 | 1213 | ``` 1214 | // ** stdio.h ** 1215 | 1216 | sprintf() - The same as printf but to a string. 1217 | sscanf() - The same as scanf but from a string. 1218 | 1219 | 1220 | // ** stdlib.h ** 1221 | 1222 | atoi() - Converts a string to a int. 1223 | atof() - Converts a string to a double. 1224 | atol() - Converts a string to a long int. 1225 | 1226 | rand() - Returns a random number. 1227 | srand() - Returns a random number given a seed. 1228 | 1229 | atexit() - Runs a function handler at the exit of the program. 1230 | 1231 | getenv() - Get environment variables or proprieties from the 1232 | system. 1233 | system() - Executes a string command on the host environment, 1234 | on the shell. 1235 | 1236 | bsearch() - Binary search. 1237 | qsort() - Quick sort. 1238 | 1239 | 1240 | // ** string.h ** 1241 | 1242 | memchr() - Returns the first occurrence of a unsigned char in a 1243 | array or memory sequence. 1244 | memcmp() - Compares the first n chars of the sequence s1 and s2. 1245 | memcpy() - Copies the first n chars from s2 to s1. 1246 | memmove() - Very similar to memcpy() but works even if the chars 1247 | overlap. 1248 | memset() - Initializes a array or a memory block with a value. 1249 | 1250 | strcat() - Concatenates a copy of s2 to s1. 1251 | strchr() - Returns the first occurrence of a char in a string. 1252 | strcmp() - Compares the chars of the sequence s1 with s2. 1253 | strcoll() - Transforms the string s1 to be suitable to be used 1254 | by memcmp() and strcmp(). 1255 | strcpy() - Copies the string pointed by s2 into a array s1. 1256 | strcspn() - Starting from s1 counts the chars that are not present 1257 | from s2. 1258 | strerror() - Returns a pointer to an error message represented by 1259 | errnum. 1260 | strlen() - Returns the length of a string (in bytes). The '\0' 1261 | is not included. 1262 | strncat() - Appends up to n characters of string s2 to the end of 1263 | string s1. 1264 | strncmp() - Equal to strcmp() but only for n characters. 1265 | strncpy() - Equal to strcpy() but only for n characters. 1266 | 1267 | strpbrk() - It locates the first character of s1 that is present in s2. 1268 | strrchr() - It locates the last occurrence of a char in the string s. 1269 | strspn() - Counts the characters of s1 until it find characters that 1270 | are not present in s2. 1271 | 1272 | strstr() - Find the first occurrence of s2 in s1. 1273 | strtok() - Divides the string into tokens. 1274 | 1275 | ``` 1276 | 1277 | ## Functions for manipulating files 1278 | 1279 | 1. Open a file. 1280 | 1281 | 2. Read and write from / to a file. 1282 | 1283 | 3. Random access. 1284 | 1285 | 4. Read / write one block at a time. 1286 | 1287 | 5. Close a file. 1288 | 1289 | ``` 1290 | // ** 1 ** 1291 | 1292 | #include 1293 | #include 1294 | 1295 | // Open a file. 1296 | 1297 | "r" - Open text file for reading. 1298 | "w" - Open text file for writing. If the file already 1299 | exists it truncates to zero length. Begin of the file. 1300 | "a" - Open the file in append mode. You write at the end of 1301 | the file. 1302 | "r+" - Open the file for reading and for writing. File position 1303 | at the beginning of the file. 1304 | "w+" - Creates a new text file for reading and for writing. 1305 | If the file already exists it will truncate the file 1306 | to zero length. 1307 | "a+" - Open an existing file or create a new one in append mode. 1308 | You can read data anywhere but you can only add data in 1309 | the end of the file. 1310 | "rb" - Open file for reading in binary. 1311 | "wb" - Open file for writing in binary. 1312 | 1313 | 1314 | FILE * open_file(char *filename){ 1315 | FILE *fp; // file pointer 1316 | 1317 | fp = fopen(filename, "r"); // r - for read 1318 | if (fp == NULL) 1319 | fprintf( stderr, "Error opening file.\n"); 1320 | return fp; 1321 | } 1322 | 1323 | // ** 2 ** 1324 | 1325 | // Read and write from / to a file. 1326 | 1327 | getc() - Macro to read one char. 1328 | fgetc() - Function that does the same as getc(). 1329 | putc() - Macro to writes one char. 1330 | fputc() - Function that does the same as putc(). 1331 | ungetc() - Pushes a character onto a file strem. 1332 | 1333 | fflush() - Flushes the buffer. 1334 | ftell() - Returns the current file position. 1335 | 1336 | fprintf() - Exactly as printf, but to a file. 1337 | fscanf() - Exactly as scanf, but from a file. 1338 | 1339 | clearerr() - Resets the error and end-of-file indicator. 1340 | feof() - Checks if EOF (End Of File) indicator was reached 1341 | in previous read operation. 1342 | ferror() - Returns the integer error code, while reading 1343 | or writing to a stream. 1344 | 1345 | tmpfile() - Creates a temporary binary file. 1346 | remove() - Removes a file from file system. 1347 | rename() - Renames a file in the file system. 1348 | setbuf() - Alter the buffer proprieties for a file. 1349 | 1350 | 1351 | #include 1352 | #include 1353 | 1354 | #define FAIL 0 1355 | #define SUCCESS 1 1356 | 1357 | int copy_text_or_bin_file(char * input_file, char * output_file){ 1358 | FILE *fp1, *fp2; 1359 | if ( (fp1 = fopen(input_file, "rb")) == NULL ) 1360 | return FAIL; 1361 | if ( (fp2 = fopen(output_file, "wb")) == NULL ) 1362 | { 1363 | fclose( fp1 ); 1364 | return FAIL; 1365 | } 1366 | while (!feof(fp1)) 1367 | putc(getc( fp1), fp2); 1368 | fclose(fp1); 1369 | fclose(fp2); 1370 | return SUCCESS; 1371 | } 1372 | 1373 | 1374 | // Line oriented reading and writing. 1375 | fgets() - Reads one line from a file stream. 1376 | fputs() - Writes one line to a file stream. 1377 | 1378 | example equal to the previous but copies line by line: 1379 | 1380 | #define LINESIZE 100 1381 | 1382 | char line[LINESIZE]; 1383 | 1384 | while( fgets( line, LINESIZE - 1, fp1 ) != NULL ) 1385 | fputs( line, fp2) 1386 | 1387 | 1388 | // ** 3 ** 1389 | 1390 | // Random access. 1391 | 1392 | fseek() - Moves the file pointer inside the file 1393 | to a random position. 1394 | 1395 | 1396 | // ** 4 ** 1397 | 1398 | // Read / write one block at a time. 1399 | 1400 | fread() - Read one block at a time. 1401 | fwrite() - Writes one block at a time. 1402 | 1403 | 1404 | // ** 5 ** 1405 | 1406 | // Close a file. 1407 | 1408 | fclose(fp) 1409 | 1410 | ``` 1411 | 1412 | ## Function pointers 1413 | 1414 | 1. Single function pointer. 1415 | 1416 | 2. Array of function pointers. 1417 | 1418 | ``` 1419 | void led_sequence(void); 1420 | 1421 | int main(void){ 1422 | 1423 | // ** 1 ** 1424 | 1425 | // Declaration of a single function pointer. 1426 | void (* const arr_pointers_to_functions) (void) = led_sequence; 1427 | 1428 | // Call the function, using the right function pointer. 1429 | (*(arr_pointers_to_functions)) (); 1430 | 1431 | 1432 | // ** 2 ** 1433 | 1434 | // Declaration of an array of pointers to functions with a parameter void and returning a void. 1435 | // Fill it with functions. 1436 | void (* const arr_pointers_to_functions[]) (void) = {led_sequence, NULL, NULL, NULL}; 1437 | 1438 | int menu_option = 0; 1439 | 1440 | // Call the function, using the right function pointer. 1441 | (*(arr_pointers_to_functions[menu_option])) (); 1442 | 1443 | } 1444 | 1445 | void led_sequence(void){ 1446 | 1447 | // ... 1448 | } 1449 | 1450 | ``` 1451 | 1452 | ## C99 - stdint.h - Primitive fixed size types 1453 | 1454 | ``` 1455 | // Include that has the primitive fixed size types. 1456 | #include 1457 | 1458 | // Types 1459 | uint8_t int8_t 1460 | uint16_t int16_t 1461 | uint32_t int32_t 1462 | uint64_t int64_t 1463 | 1464 | ``` 1465 | 1466 | ## Preprocessor Macros 1467 | 1468 | 1. Always put the Macro inside parenthesis, so that the order of execution is always the same. 1469 | 1470 | ``` 1471 | #define RCC_APB2_ENR_ADDR (RCC_BASE_ADDR + RCC_APB2_ENR_OFFSET) 1472 | 1473 | ``` 1474 | 1475 | 2. Always protect the **.h** file content against multiple inclusion on the same .C file. 1476 | 1477 | ``` 1478 | #ifndef REG_BASE_ADDRESSES_H 1479 | #define REG_BASE_ADDRESSES_H 1480 | 1481 | // content of the include file reg_base_addresses.h 1482 | 1483 | #endif 1484 | 1485 | ``` 1486 | 1487 | ## Technique for defining more than one statement in a preprocessor Macro. 1488 | 1489 | ``` 1490 | // This is a technique in C programming to execute multiple C statements using a single C macro. 1491 | // Placing a do__while loop that only executes once. 1492 | #define GPIO_G_SET() do{ (GPIOA->MODE |= (1 << 0)); (GPIOA->MODE &= ~(1 << 0)); }while(0) 1493 | 1494 | ``` 1495 | 1496 | ## C for Embedded Systems 1497 | 1498 | 1. How to define registers based on the Memory Map base address of the peripheral and a specific register offset of that peripheral? 1499 | 1500 | 2. How to SET and Clear bit's on a register? 1501 | 1502 | 3. How to test if one bit transition from 0 to 1, that is bit 18? 1503 | 1504 | ``` 1505 | // Include that has the primitive fixed size types. 1506 | #include 1507 | 1508 | 1509 | // ** 1 ** 1510 | 1511 | // Register that Enables the RCC peripheral Clock. 1512 | #define RCC_BASE_ADDR 0x40012000UL 1513 | #define RCC_APB2_ENR_OFFSET 0x44UL 1514 | #define RCC_APB2_ENR_ADDR (RCC_BASE_ADDR + RCC_APB2_ENR_OFFSET) 1515 | 1516 | // Register of the ADC enable of random bit. 1517 | #define ADC_BASE_ADDR 0x42012000UL 1518 | #define ADC_CR1_REG_OFFSET 0x04UL 1519 | #define ADC_CR1_REG_ADDR (ADC_BASE_ADDR + ADC_CR1_REG_OFFSET) 1520 | 1521 | int main(void){ 1522 | 1523 | // ** 2 ** 1524 | 1525 | // The following case makes a set of one bit to '1'. 1526 | 1527 | // Register that enables the RCC peripheral Clock on bit 9th. 1528 | uint32_t volatile *pRccApb2Enr = (uint32_t *) RCC_APB2_ENR_ADDR; 1529 | *pRccApb2Enr |= (1 << 8) 1530 | 1531 | 1532 | // The following case makes a clear of one bit to '0'. 1533 | 1534 | // Register of the ADC that we will clear the 9th bit. 1535 | uint32_t volatile *pAdcCr1Reg = (uint32_t *) ADC_CR1_REG_ADDR; 1536 | *pAdcCr1Reg &= ~(1 << 8) 1537 | 1538 | 1539 | // The following case makes the Clear of the value 3 -> ~'11' that is '00' 1540 | // and set's the value 2 -> '10'. 1541 | 1542 | uint32_t volatile * pGPIOAModeReg = (uint32_t *) (GPIOA_BASE_ADDR + 0x00) // + offset address. 1543 | 1544 | *pGPIOAModeReg &= ~(0x3 << 16); // **Clear** 1545 | *pGPIOAModeReg |= (0x2 << 16); // **Set** 1546 | 1547 | 1548 | // ** 3 ** 1549 | 1550 | // We test if one bit transition from 0 to 1, that is bit 18. 1551 | while( !(*pGPIOA_IOR_Reg & (1 << 18)) ); 1552 | } 1553 | 1554 | ``` 1555 | 1556 | ## Keyword **const** and **volatile** 1557 | 1558 | 1. The keyword **const** means that the it is constant, the content data or the address of the pointer. 1559 | 1560 | 2. The keyword **volatile** means that the content data or the address of the pointer is never optimized away by the compiler -O2 or something, because each time it is used a fresh copy of the data as to be fetched from memory. It is very useful, when dealing with registers on a microController or when several simultaneous threads are executing, or when a main thread is executing and a ISR will interrupt the main processing thread. Because code can be interrupted every access to this volatile variable should be fetched again from the memory or memory mapped register. 1561 | 1562 | ``` 1563 | #define SRAM_ADDRESS1 0x20000000UL 1564 | 1565 | // This means that the content of the pointer is "volatile". 1566 | uint32_t volatile *p = (uint32_t *) SRAM_ADDRESS1; 1567 | 1568 | // This means that the address of the pointer is "volatile". 1569 | uint32_t * volatile p = (uint32_t *) SRAM_ADDRESS1; 1570 | 1571 | // This means that the content of the data is volatile and the address of the pointer is "volatile". 1572 | uint32_t volatile * volatile p = (uint32_t *) SRAM_ADDRESS1; 1573 | 1574 | 1575 | // ... and the same logic and places to the keyword "const". 1576 | 1577 | ``` 1578 | 1579 | ## Sizes for 32 bit microController 1580 | 1581 | - **Byte** : data of 8-bit length. 1582 | - **Half word** : data of 16-bit length. 1583 | - **Word** : data of **32-bit** length. Because the microController is a 32 bit's microController. 1584 | - **Double word** : data of 64-bit length. 1585 | 1586 | 1587 | ## Two ways of making a Menu with strings - char * - and send it to UART. 1588 | 1589 | 1. The complex way... 1590 | 1591 | ``` 1592 | // Menu text to TX: 1593 | char const * message_0 = "\n\n\n Menu\n\n"; 1594 | char const * message_1 = "1. LED animation.\n"; 1595 | char const * message_2 = "2. Option 2.\n"; 1596 | char const * message_3 = "3. Option 3.\n"; 1597 | char const * message_4 = "4. Option 4.\n\n"; 1598 | char const * all_messages[] = {message_0, message_1, message_2, message_3, message_4 }; 1599 | 1600 | uint32_t all_messages_size = sizeof(all_messages) / sizeof(all_messages[0]); 1601 | for(int i=0; i < all_messages_size; i++){ 1602 | HAL_UART_Transmit(&huart2, (uint8_t *) all_messages[i], (uint16_t) strlen(all_messages[i]), 1603 | timeout); 1604 | } 1605 | 1606 | ``` 1607 | 1608 | 2. The simple way ... 1609 | 1610 | ``` 1611 | #include 1612 | 1613 | ... 1614 | 1615 | // Menu text to TX: 1616 | char const * message = "\n\n\n Menu\n\n" 1617 | "1. LED animation.\n" 1618 | "2. Option 2.\n" 1619 | "3. Option 3.\n" 1620 | "4. Option 4.\n\n"; 1621 | 1622 | HAL_UART_Transmit(&huart2, (uint8_t *) message, (uint16_t) strlen(message), 1623 | timeout); 1624 | 1625 | ``` 1626 | 1627 | # Utils 1628 | 1629 | ## Abstract Double Linked List - jco_list 1630 | 1631 | This is a Abstract Double Linked List, called jco_list and it's license is MIT Open Source.
1632 | The list interface follows. To see examples of the list usage see the tests inside the main.c source code file. 1633 | 1634 | ``` 1635 | typedef struct node{ 1636 | void * elem; 1637 | struct node * next; 1638 | struct node * prev; 1639 | } NODE; 1640 | 1641 | typedef struct{ 1642 | NODE * firstNode; 1643 | NODE * lastNode; 1644 | int size; 1645 | NODE * iterator; 1646 | } LST; 1647 | 1648 | typedef enum { LST_D_UP, LST_D_DOWN } LST_DIRECTION; 1649 | 1650 | 1651 | LST * lst_new(/* NULL or pointer to function equals == */); 1652 | bool lst_free(LST * lstObj); 1653 | 1654 | int lst_size(LST * lstObj); 1655 | 1656 | void * lst_get_first(LST * lstObj); 1657 | void * lst_get_last(LST * lstObj); 1658 | void * lst_get_at(LST * lstObj, int pos); 1659 | 1660 | // Returns the previous existing element in that pos. 1661 | void * lst_set(LST * lstObj, void * elem, int pos); 1662 | 1663 | bool lst_insert_first(LST * lstObj, void * elem); 1664 | bool lst_insert_last(LST * lstObj, void * elem); 1665 | bool lst_insert_at(LST * lstObj, void * elem, int pos); 1666 | 1667 | // Receives a pointer to a function compare that as 1668 | // 2 parameters "a" and "b" and returns int, 1669 | // 1 if a > b, 0 if a == b and -1 if a < b. 1670 | bool lst_insert_ordered(LST * lstObj, void * elem, 1671 | int (* const ptr_to_funct_cmp) (void * a, void * b ) ); 1672 | 1673 | void * lst_remove_first(LST * lstObj); 1674 | void * lst_remove_last(LST * lstObj); 1675 | void * lst_remove_at(LST * lstObj, int pos); 1676 | 1677 | // Iterators NEXT and PREV. 1678 | bool lst_iter_get_first(LST * lstObj); 1679 | bool lst_iter_get_last(LST * lstObj); 1680 | void * lst_iter_next(LST * lstObj); 1681 | void * lst_iter_prev(LST * lstObj); 1682 | bool lst_iter_is_begin(LST * lstObj); 1683 | bool lst_iter_is_end(LST * lstObj); 1684 | 1685 | void * lst_find(LST * lstObj, void * elem, 1686 | int (* const ptr_to_funct_cmp) (void * a, void * b), 1687 | LST_DIRECTION direction, 1688 | NODE * currNode, 1689 | NODE ** foundNode); 1690 | 1691 | int cmp_int(void * aIn, void * bIn); 1692 | int cmp_float(void * aIn, void * bIn); 1693 | int cmp_double(void * aIn, void * bIn); 1694 | int cmp_single_char(void * aIn, void * bIn); 1695 | int cmp_null_term_str(void * aIn, void * bIn); 1696 | 1697 | ``` 1698 | 1699 | # TODO: 1700 | -Implement a abstract ArrayList.
1701 | -Implement a abstract HashTable.
1702 | 1703 | # Have fun! 1704 | Best regards,
1705 | Joao Nuno Carvalho -------------------------------------------------------------------------------- /utils/jco_list.c: -------------------------------------------------------------------------------- 1 | /******************************************************************* 2 | * Name: Abstract Double Linked List - jco_list.h and jco_list.c * 3 | * Author: Joao Nuno Carvalho * 4 | * Date: 2020.07.26 * 5 | * License: MIT Open Source Licence * 6 | * Files: jco_list.h * 7 | * jco_list.c * 8 | * main.c (Test and example of usage code) * 9 | ******************************************************************** 10 | * Notes: Read the main.c for examples on usage of this * 11 | * Abstract Double Linked List. * 12 | *******************************************************************/ 13 | 14 | #include 15 | #include 16 | #include 17 | #include "jco_list.h" 18 | 19 | ///////// 20 | // Compare functions 21 | 22 | // Note: You can add in your code a custom one for your dataType. 23 | 24 | int cmp_int(void * aIn, void * bIn){ 25 | int * a = (int *) aIn; 26 | int * b = (int *) bIn; 27 | if (*a == *b) 28 | return 0; 29 | else if (*a > *b) 30 | return 1; 31 | else // if (*a < *b) 32 | return -1; 33 | } 34 | 35 | int cmp_float(void * aIn, void * bIn){ 36 | float * a = (float *) aIn; 37 | float * b = (float *) bIn; 38 | if (*a == *b) 39 | return 0; 40 | else if (*a > *b) 41 | return 1; 42 | else // if (*a < *b) 43 | return -1; 44 | } 45 | 46 | int cmp_double(void * aIn, void * bIn){ 47 | double * a = (double *) aIn; 48 | double * b = (double *) bIn; 49 | if (*a == *b) 50 | return 0; 51 | else if (*a > *b) 52 | return 1; 53 | else // if (*a < *b) 54 | return -1; 55 | } 56 | 57 | int cmp_single_char(void * aIn, void * bIn){ 58 | char * a = (char *) aIn; 59 | char * b = (char *) bIn; 60 | return strncmp(a, b, 1); 61 | } 62 | 63 | int cmp_null_term_str(void * aIn, void * bIn){ 64 | char * a = (char *) aIn; 65 | char * b = (char *) bIn; 66 | return strcmp(a, b); 67 | } 68 | 69 | ////////// 70 | // List functions. 71 | 72 | /* 73 | Returns: 74 | The LST object allocated 75 | or NULL in case of error allocating the object memory. 76 | 77 | ERRORS: 78 | See stderr for the errors. 79 | */ 80 | LST * lst_new(/* NULL or pointer to function equals == */){ 81 | LST * obj = (LST *) malloc(sizeof(LST)); 82 | if (obj == NULL){ 83 | fprintf(stderr, "ERROR: jco_list in func lst_new: error while allocating the obj memory.\n"); 84 | return NULL; 85 | } 86 | obj->firstNode = NULL; 87 | obj->lastNode = NULL; 88 | obj->iterator = NULL; 89 | obj->size = 0; 90 | return obj; 91 | } 92 | 93 | 94 | /* 95 | Parameters: 96 | LST * lstObj - This is a list object created with the lst_new() func. 97 | 98 | Returns: 99 | true if the memory was made free, 100 | or false if the lstObj was in an incorrect state to be free. 101 | 102 | ERRORS: 103 | See stderr for the errors. 104 | */ 105 | bool lst_free(LST * lstObj){ 106 | if (lstObj == NULL){ 107 | fprintf(stderr, "ERROR: jco_list in func lst_free: lstObj is NULL!\n"); 108 | return false; 109 | }else if ( (*lstObj).size != 0){ 110 | fprintf(stderr, 111 | "ERROR: jco_list in func lst_free: lstObj has %d elements!\n", (*lstObj).size); 112 | return false; 113 | }else if ( (*lstObj).firstNode != NULL 114 | || (*lstObj).lastNode != NULL 115 | // || (*lstObj).iterator != NULL 116 | ){ 117 | fprintf(stderr, 118 | "ERROR: jco_list in func lst_free: lstObj has incoherent state!\n"); 119 | return false; 120 | }else{ 121 | // DEBUG Uncomment. 122 | free(lstObj); 123 | return true; 124 | } 125 | } 126 | 127 | 128 | /* 129 | Parameters: 130 | LST * lstObj - This is a list object created with the lst_new() func. 131 | 132 | Returns: 133 | int - The number of elements in the list. 134 | or a negative number in case of error. 135 | 136 | ERRORS: 137 | See stderr for the errors. 138 | */ 139 | int lst_size(LST * lstObj){ 140 | if (lstObj == NULL){ 141 | fprintf(stderr, "ERROR: jco_list in func lst_size: lstObj is NULL!\n"); 142 | return -1; 143 | }else if ( (*lstObj).size < 0){ 144 | fprintf(stderr, 145 | "ERROR: jco_list in func lst_size: lstObj has impossible size of %d elements!\n", (*lstObj).size); 146 | } 147 | return (*lstObj).size; 148 | } 149 | 150 | 151 | ///////// 152 | // GET 153 | 154 | /* 155 | NOTE: Alias for lst_get_at() pos = 0. 156 | 157 | Parameters: 158 | LST * lstObj - This is a list object created with the lst_new() func. 159 | 160 | Returns: 161 | void * - The element in the pos, you can't deallocate it's memory. 162 | In case of error it return NULL. 163 | 164 | ERRORS: 165 | See stderr for the errors. 166 | */ 167 | void * lst_get_first(LST * lstObj){ 168 | int pos = 0; 169 | return lst_get_at(lstObj, pos); 170 | } 171 | 172 | 173 | /* 174 | NOTE: Alias for lst_get_at() pos = last element. 175 | 176 | Parameters: 177 | LST * lstObj - This is a list object created with the lst_new() func. 178 | 179 | Returns: 180 | void * - The element in the pos, you can't deallocate it's memory. 181 | In case of error it return NULL. 182 | 183 | ERRORS: 184 | See stderr for the errors. 185 | */ 186 | void * lst_get_last(LST * lstObj){ 187 | int pos = lst_size(lstObj) - 1; 188 | return lst_get_at(lstObj, pos); 189 | } 190 | 191 | 192 | /* 193 | Parameters: 194 | LST * lstObj - This is a list object created with the lst_new() func. 195 | 196 | pos - Pos of the element. 0 <= pos < size - 1 . 197 | 198 | Returns: 199 | void * - The element in the pos, you can't deallocate it's memory. 200 | In case of error it return NULL. 201 | 202 | ERRORS: 203 | See stderr for the errors. 204 | */ 205 | void * lst_get_at(LST * lstObj, int pos){ 206 | if (lstObj == NULL){ 207 | fprintf(stderr, "ERROR: jco_list in func lst_get_at: lstObj is NULL!\n"); 208 | return NULL; 209 | }else if ( pos < 0 || pos >= lstObj->size ){ 210 | fprintf(stderr, "ERROR: jco_list in func lst_get_at: pos out of bounds, 0 <= pos < size !\n"); 211 | return NULL; 212 | }else{ 213 | NODE * currNode = NULL; 214 | // Decide if start from the begin or from the end? 215 | // Find the node corresponding to the position before the position. 216 | if ((float)pos <= (float)lstObj->size / 2){ 217 | // First half of the list. 218 | currNode = lstObj->firstNode; 219 | for(int i = 1; i <= pos; ++i){ 220 | currNode = currNode->next; 221 | } 222 | }else{ 223 | // Second half of the list. 224 | // From last pos to the begining (last half). 225 | currNode = lstObj->lastNode; 226 | for(int i = lstObj->size - 2; i >= pos; --i){ 227 | currNode = currNode->prev; 228 | } 229 | } 230 | return currNode->elem; 231 | } 232 | } 233 | 234 | 235 | 236 | ////// 237 | // SET 238 | 239 | /* 240 | Parameters: 241 | LST * lstObj - This is a list object created with the lst_new() func. 242 | 243 | void * elem - The element to be added, a previously allocated element. 244 | 245 | pos - Pos of the element. 0 <= pos < size - 1 . 246 | 247 | Returns: 248 | void * - The element that was previously in the pos, you have to 249 | deallocate it's memory. 250 | In case of error it return NULL. 251 | 252 | ERRORS: 253 | See stderr for the errors. 254 | */ 255 | void * lst_set(LST * lstObj, void * elem, int pos){ 256 | if (lstObj == NULL){ 257 | fprintf(stderr, "ERROR: jco_list in func lst_set: lstObj is NULL!\n"); 258 | return false; 259 | }else if (elem == NULL){ 260 | fprintf(stderr, "ERROR: jco_list in func lst_set: elem is NULL!\n"); 261 | return false; 262 | }else if ( pos < 0 && pos >= lstObj->size ){ 263 | fprintf(stderr, "ERROR: jco_list in func lst_set: pos out of bounds, 0 <= pos < size !\n"); 264 | return false; 265 | }else{ 266 | NODE * currNode = NULL; 267 | // Decide if start from the begin or from the end? 268 | // Find the node corresponding to the position before the position. 269 | if ((float)pos <= (float)lstObj->size / 2){ 270 | // First half of the list. 271 | // pos == 0 272 | currNode = lstObj->firstNode; 273 | // pos > 0 274 | for(int i=1; i <= pos; ++i){ 275 | currNode = currNode->next; 276 | } 277 | }else{ 278 | // Second half of the list. 279 | // From last pos to the begining (last half). 280 | // pos == size - 1 (last pos) 281 | currNode = lstObj->lastNode; 282 | // down to i == pos 283 | for(int i = lstObj->size - 1; i > pos; --i){ 284 | currNode = currNode->prev; 285 | } 286 | } 287 | void * tmpElem = currNode->elem; 288 | currNode->elem = elem; 289 | return tmpElem; 290 | } 291 | } 292 | 293 | // aqui 294 | 295 | 296 | ///////// 297 | // INSERT 298 | 299 | /* 300 | NOTE: Alias for lst_insert_at() pos = 0. 301 | 302 | Parameters: 303 | LST * lstObj - This is a list object created with the lst_new() func. 304 | 305 | void * elem - The element to be added, a previously allocated element. 306 | 307 | Returns: 308 | bool - In case of error while inserting a new element in the list. 309 | 310 | ERRORS: 311 | See stderr for the errors. 312 | */ 313 | bool lst_insert_first(LST * lstObj, void * elem){ 314 | int pos = 0; 315 | return lst_insert_at(lstObj, elem, pos); 316 | } 317 | 318 | 319 | /* 320 | NOTE: Alias for lst_insert_at() pos = last element + 1. 321 | 322 | Parameters: 323 | LST * lstObj - This is a list object created with the lst_new() func. 324 | 325 | void * elem - The element to be added, a previously allocated element. 326 | 327 | Returns: 328 | bool - In case of error while inserting a new element in the list. 329 | 330 | ERRORS: 331 | See stderr for the errors. 332 | */ 333 | bool lst_insert_last(LST * lstObj, void * elem){ 334 | int pos = lst_size(lstObj); 335 | return lst_insert_at(lstObj, elem, pos); 336 | } 337 | 338 | 339 | /* 340 | Parameters: 341 | LST * lstObj - This is a list object created with the lst_new() func. 342 | 343 | void * elem - The element to be added, a previously allocated element. 344 | 345 | pos - Pos of the element to be inserted. 0 <= pos <= size - 1 . 346 | 347 | Returns: 348 | bool - In case of error while inserting a new element in the list. 349 | 350 | ERRORS: 351 | See stderr for the errors. 352 | */ 353 | bool lst_insert_at(LST * lstObj, void * elem, int pos){ 354 | if (lstObj == NULL){ 355 | fprintf(stderr, "ERROR: jco_list in func lst_insert_at: lstObj is NULL!\n"); 356 | return false; 357 | }else if (elem == NULL){ 358 | fprintf(stderr, "ERROR: jco_list in func lst_insert_at: elem is NULL!\n"); 359 | return false; 360 | }else if ( pos < 0 && pos > lstObj->size ){ 361 | fprintf(stderr, "ERROR: jco_list in func lst_insert_at: pos out of bounds, 0 <= pos <= size !\n"); 362 | return false; 363 | }else{ 364 | NODE * nodeToBeInserted = (NODE *) malloc(sizeof(NODE)); 365 | if (nodeToBeInserted == NULL){ 366 | fprintf(stderr, "ERROR: jco_list in func lst_insert_at: while allocating NODE!\n"); 367 | return false; 368 | } 369 | 370 | NODE * currNode = NULL; 371 | // Decide if start from the begin or from the end? 372 | // Find the node corresponding to the position before the position. 373 | if ((float)pos <= (float)lstObj->size / 2){ 374 | // First half of the list. 375 | if (lstObj->firstNode == NULL) 376 | currNode = NULL; 377 | else{ 378 | if (pos == 0) 379 | currNode = NULL; 380 | else{ 381 | // pos >= 1 ==> currNode >= 0 382 | currNode = lstObj->firstNode; 383 | // Goes to pos >= 2. 384 | for(int i=1; i <= pos - 1; ++i){ 385 | currNode = currNode->next; 386 | } 387 | } 388 | } 389 | }else{ 390 | // Second half of the list. 391 | // From last pos to the begining (last half). 392 | if (lstObj->lastNode == NULL) 393 | currNode = NULL; 394 | else{ 395 | if (pos == 0) 396 | currNode = NULL; 397 | else{ 398 | // pos >= 1 ==> currNode <= last node 399 | currNode = lstObj->lastNode; 400 | // Goes to pos >= 2. 401 | for(int i = lstObj->size - 2; i >= pos - 1; --i){ 402 | currNode = currNode->prev; 403 | } 404 | } 405 | } 406 | } 407 | 408 | // Fill the node fields. 409 | nodeToBeInserted->elem = elem; 410 | if (pos == 0 && lstObj->firstNode == NULL){ 411 | // Adding when the list is empty. 412 | nodeToBeInserted->prev = NULL; 413 | nodeToBeInserted->next = NULL; 414 | lstObj->firstNode = nodeToBeInserted; 415 | lstObj->lastNode = nodeToBeInserted; 416 | }else if (pos == 0){ 417 | // Adding at the end when size != 0. 418 | nodeToBeInserted->prev = NULL; 419 | nodeToBeInserted->next = lstObj->firstNode; 420 | lstObj->firstNode = nodeToBeInserted; 421 | // lstObj->lastNode = ; // We don't change. 422 | // Node N + 1 423 | nodeToBeInserted->next->prev = nodeToBeInserted; 424 | // Node N - 1 425 | // currNode->next = ; // It doesn't exists. 426 | }else if (pos == lstObj->size){ 427 | // Adding at the end when size != 0. 428 | nodeToBeInserted->prev = currNode; 429 | nodeToBeInserted->next = NULL; 430 | // lstObj->firstNode = ; // We don't change. 431 | lstObj->lastNode = nodeToBeInserted; 432 | // Node N + 1 433 | // currNode->next->prev = ; // It doesn't exists. 434 | // Node N - 1 435 | currNode->next = nodeToBeInserted; 436 | }else{ 437 | // Adding in the middle when size != 0. 438 | nodeToBeInserted->prev = currNode; 439 | nodeToBeInserted->next = currNode->next; 440 | // Node N + 1 441 | currNode->next->prev = nodeToBeInserted; 442 | // Node N - 1 443 | currNode->next = nodeToBeInserted; 444 | } 445 | 446 | lstObj->size++; 447 | return true; 448 | } 449 | } 450 | 451 | 452 | /* 453 | 454 | Parameters: 455 | LST * lstObj - This is a list object created with the lst_new() func. 456 | 457 | void * elem - The element to be added, a previously allocated element. 458 | 459 | ptr_to_funct_cmp - Receives a pointer to a function compare that as 460 | 2 parameters "a" and "b" and returns int, 461 | 1 if a > b, 0 if a == b and -1 if a < b. 462 | 463 | The function as the following example implementation: 464 | 465 | int cmp_int(void * aIn, void * bIn ){ 466 | int * a = (int *) aIn; 467 | int * b = (int *) bIn; 468 | if (*a > *b) 469 | return 1; 470 | else if (*a < *b) 471 | return -1; 472 | else 473 | return 0; 474 | } 475 | 476 | Returns: 477 | bool - In case of error while inserting a new element in the list. 478 | 479 | ERRORS: 480 | See stderr for the errors. 481 | */ 482 | bool lst_insert_ordered(LST * lstObj, void * elem, 483 | int (* const ptr_to_funct_cmp) (void * a, void * b ) ){ 484 | 485 | if (lstObj == NULL){ 486 | fprintf(stderr, "ERROR: jco_list in func lst_insert_ordered: lstObj is NULL!\n"); 487 | return false; 488 | }else if (elem == NULL){ 489 | fprintf(stderr, "ERROR: jco_list in func lst_insert_ordered: elem is NULL!\n"); 490 | return false; 491 | }else if ( ptr_to_funct_cmp == NULL ){ 492 | fprintf(stderr, 493 | "ERROR: jco_list in func lst_insert_ordered: pointer to function compare is NULL !\n"); 494 | return false; 495 | }else{ 496 | NODE * nodeToBeInserted = (NODE *) malloc(sizeof(NODE)); 497 | if (nodeToBeInserted == NULL){ 498 | fprintf(stderr, 499 | "ERROR: jco_list in func lst_insert_ordered: while allocating NODE!\n"); 500 | return false; 501 | } 502 | 503 | NODE * currNode = NULL; 504 | nodeToBeInserted->elem = elem; 505 | 506 | // Decide if start from the begin or from the end? 507 | // Find the node corresponding to the position before the position. 508 | if (lstObj->firstNode == NULL){ 509 | currNode = NULL; 510 | // Adding when the list is empty. 511 | nodeToBeInserted->prev = NULL; 512 | nodeToBeInserted->next = NULL; 513 | lstObj->firstNode = nodeToBeInserted; 514 | lstObj->lastNode = nodeToBeInserted; 515 | }else{ 516 | currNode = lstObj->firstNode; 517 | 518 | while(currNode != NULL){ 519 | void * a = elem; 520 | void * b = currNode->elem; 521 | int cmp_val = (* ptr_to_funct_cmp) (a, b); 522 | if(cmp_val == -1 || cmp_val == 0){ 523 | // Add before currNode. 524 | 525 | if (currNode == lstObj->firstNode){ 526 | // POS 0. 527 | // Adding at the begin when size != 0. 528 | nodeToBeInserted->prev = NULL; 529 | nodeToBeInserted->next = lstObj->firstNode; 530 | lstObj->firstNode = nodeToBeInserted; 531 | // lstObj->lastNode = ; // We don't change. 532 | // Node N + 1 533 | nodeToBeInserted->next->prev = nodeToBeInserted; 534 | // Node N - 1 535 | // currNode->next = ; // It doesn't exists. 536 | } else { 537 | // Pos >= 1 538 | // Adding in the middle when size != 0. 539 | nodeToBeInserted->prev = currNode->prev; 540 | nodeToBeInserted->next = currNode; 541 | // Node N + 1 542 | NODE * prev = currNode->prev; 543 | if (prev != NULL) 544 | prev->next = nodeToBeInserted; 545 | // Node N - 1 546 | currNode->prev = nodeToBeInserted; 547 | } 548 | break; 549 | } else { 550 | // Search for next node and compare again. 551 | currNode = currNode->next; 552 | 553 | // Have to add someware after currNode. 554 | } 555 | } 556 | if (currNode == NULL){ 557 | currNode = lstObj->lastNode; 558 | // We will add at the end of the list after currNode. 559 | // Adding at the end when size != 0. 560 | nodeToBeInserted->prev = currNode; 561 | nodeToBeInserted->next = NULL; 562 | // lstObj->firstNode = ; // We don't change. 563 | lstObj->lastNode = nodeToBeInserted; 564 | // Node N + 1 565 | // currNode->next->prev = ; // It doesn't exists. 566 | // Node N - 1 567 | currNode->next = nodeToBeInserted; 568 | } 569 | } 570 | lstObj->size++; 571 | return true; 572 | } 573 | } 574 | 575 | 576 | 577 | ///////// 578 | // REMOVE 579 | 580 | /* 581 | NOTE: Alias for lst_remove_at() pos = 0. 582 | 583 | Parameters: 584 | LST * lstObj - This is a list object created with the lst_new() func. 585 | 586 | Returns: 587 | void * - The pointer do the object encapsulated that as to be free (the memory), 588 | in case of error of parameters, returns NULL. 589 | It also return NULL if there are no elements in the list. 590 | 591 | ERRORS: 592 | See stderr for the errors. 593 | */ 594 | void * lst_remove_first(LST * lstObj){ 595 | if ( lstObj->size == 0 ){ 596 | fprintf(stderr, 597 | "ERROR: jco_list in func lst_remove_first: list has no elements!\n"); 598 | return NULL; 599 | }else{ 600 | int pos = 0; 601 | return lst_remove_at(lstObj, pos); 602 | } 603 | } 604 | 605 | 606 | /* 607 | NOTE: Alias for lst_remove_at() pos = last elem pos. 608 | 609 | Parameters: 610 | LST * lstObj - This is a list object created with the lst_new() func. 611 | 612 | Returns: 613 | void * - The pointer do the object encapsulated that as to be free (the memory), 614 | in case of error of parameters, returns NULL. 615 | It also return NULL if there are no elements in the list. 616 | 617 | ERRORS: 618 | See stderr for the errors. 619 | */ 620 | void * lst_remove_last(LST * lstObj){ 621 | if ( lstObj->size == 0 ){ 622 | fprintf(stderr, 623 | "ERROR: jco_list in func lst_remove_last: list has no elements!\n"); 624 | return NULL; 625 | }else{ 626 | int pos = lst_size(lstObj) - 1; 627 | return lst_remove_at(lstObj, pos); 628 | } 629 | } 630 | 631 | /* 632 | Parameters: 633 | LST * lstObj - This is a list object created with the lst_new() func. 634 | 635 | Returns: 636 | void * - The pointer do the object encapsulated that as to be free (the memory), 637 | in case of error of parameters, returns NULL. 638 | 639 | ERRORS: 640 | See stderr for the errors. 641 | */ 642 | void * lst_remove_at(LST * lstObj, int pos){ 643 | if (lstObj == NULL){ 644 | fprintf(stderr, "ERROR: jco_list in func lst_remove_at: lstObj is NULL!\n"); 645 | return NULL; 646 | }else if (pos < 0 ){ 647 | fprintf(stderr, "ERROR: jco_list in func lst_remove_at: pos is negative!\n"); 648 | return NULL; 649 | }else if (pos > (lstObj->size - 1) ){ 650 | fprintf(stderr, 651 | "ERROR: jco_list in func lst_remove_at: pos greater then max elements in the list!\n"); 652 | return NULL; 653 | }else { 654 | NODE * currNode = NULL; 655 | // Decide if start from the begin or from the end? 656 | if ((float)pos <= (float)lstObj->size / 2){ 657 | // First half of the list. 658 | // Zero pos case. 659 | currNode = lstObj->firstNode; 660 | // Goes to pos > 0. 661 | for(int i=1; i <= pos; ++i){ 662 | currNode = currNode->next; 663 | } 664 | }else{ 665 | // Second half of the list. 666 | // Last last pos case. 667 | currNode = lstObj->lastNode; 668 | // Goes to pos > 0. 669 | for(int i = lstObj->size - 2; i >= pos; --i){ 670 | currNode = currNode->prev; 671 | } 672 | } 673 | // Element to return to be free by the user. 674 | void * retElem = currNode->elem; 675 | // Zero case LST start pointer. 676 | if (pos == 0){ 677 | lstObj->firstNode = currNode->next; 678 | } 679 | // Last case LST end pointer. 680 | if (pos == lstObj->size - 1){ 681 | lstObj->lastNode = currNode->prev; 682 | } 683 | NODE * prevNode = currNode->prev; 684 | if (prevNode != NULL) 685 | prevNode->next = currNode->next; 686 | NODE * nextNode = currNode->next; 687 | if (nextNode != NULL) 688 | nextNode->prev = currNode->prev; 689 | // DEBUG: Uncomment. 690 | free(currNode); 691 | lstObj->size--; 692 | return retElem; 693 | } 694 | } 695 | 696 | 697 | /////////// 698 | // Iterator 699 | 700 | bool lst_iter_get_first(LST * lstObj){ 701 | if (lstObj == NULL){ 702 | fprintf(stderr, "ERROR: jco_list in func lst_iter_get_first: lstObj is NULL!\n"); 703 | return false; 704 | } else { 705 | if (lstObj->firstNode == NULL) 706 | return false; 707 | lstObj->iterator = lstObj->firstNode; 708 | return true; 709 | } 710 | } 711 | 712 | 713 | bool lst_iter_get_last(LST * lstObj){ 714 | if (lstObj == NULL){ 715 | fprintf(stderr, "ERROR: jco_list in func lst_iter_get_last: lstObj is NULL!\n"); 716 | return false; 717 | } else { 718 | if (lstObj->lastNode == NULL) 719 | return false; 720 | lstObj->iterator = lstObj->lastNode; 721 | return true; 722 | } 723 | } 724 | 725 | 726 | void * lst_iter_next(LST * lstObj){ 727 | if (lstObj == NULL){ 728 | fprintf(stderr, "ERROR: jco_list in func lst_iter_next: lstObj is NULL!\n"); 729 | return NULL; 730 | } else { 731 | if (lstObj->iterator == NULL) 732 | return NULL; 733 | else{ 734 | // Makes a ptr to the curr Iterator. 735 | NODE * lastNode = lstObj->iterator; 736 | // Advances the iterator. 737 | lstObj->iterator = lastNode->next; 738 | // Returns the element. 739 | return lastNode->elem; 740 | } 741 | } 742 | } 743 | 744 | 745 | void * lst_iter_prev(LST * lstObj){ 746 | if (lstObj == NULL){ 747 | fprintf(stderr, "ERROR: jco_list in func lst_iter_prev: lstObj is NULL!\n"); 748 | return NULL; 749 | } else { 750 | if (lstObj->iterator == NULL) 751 | return NULL; 752 | else{ 753 | // Makes a ptr to the curr Iterator. 754 | NODE * lastNode = lstObj->iterator; 755 | // Advances the iterator to the previous. 756 | lstObj->iterator = lastNode->prev; 757 | // Returns the element. 758 | return lastNode->elem; 759 | } 760 | } 761 | } 762 | 763 | 764 | bool lst_iter_is_begin(LST * lstObj){ 765 | if (lstObj == NULL){ 766 | fprintf(stderr, "ERROR: jco_list in func lst_iter_next: lstObj is NULL!\n"); 767 | return false; 768 | } else { 769 | if (lstObj->iterator == NULL) 770 | return true; 771 | else 772 | return false; 773 | 774 | } 775 | } 776 | 777 | 778 | bool lst_iter_is_end(LST * lstObj){ 779 | if (lstObj == NULL){ 780 | fprintf(stderr, "ERROR: jco_list in func lst_iter_next: lstObj is NULL!\n"); 781 | return false; 782 | } else { 783 | if (lstObj->iterator == NULL) 784 | return true; 785 | else 786 | return false; 787 | } 788 | } 789 | 790 | 791 | /* 792 | 793 | Parameters: 794 | LST * lstObj - This is a list object created with the lst_new() func. 795 | 796 | void * elem - The element to be added, a previously allocated element. 797 | 798 | ptr_to_funct_cmp - Receives a pointer to a function compare that as 799 | 2 parameters "a" and "b" and returns int, 800 | 1 if a > b, 0 if a == b and -1 if a < b. 801 | 802 | The function as the following example implementation: 803 | 804 | int cmp_int(void * aIn, void * bIn ){ 805 | int * a = (int *) aIn; 806 | int * b = (int *) bIn; 807 | if (*a > *b) 808 | return 1; 809 | else if (*a < *b) 810 | return -1; 811 | else 812 | return 0; 813 | } 814 | 815 | LST_DIRECTION direction - 816 | LST_UP - From start to end. 817 | LST_DOWN - From end to start. 818 | 819 | NODE * currNode - Pointer to start from. 820 | 821 | NODE ** foundNode - Pointer to pointer to found Node. 822 | 823 | Returns: 824 | void * - Returns ptr to element. 825 | In case of error or element not found return NULL. 826 | 827 | ERRORS: 828 | See stderr for the errors. 829 | */ 830 | void * lst_find(LST * lstObj, void * elem, 831 | int (* const ptr_to_funct_cmp) (void * a, void * b), 832 | LST_DIRECTION direction, 833 | NODE * currNode, 834 | NODE ** foundNode){ 835 | 836 | if (lstObj == NULL){ 837 | fprintf(stderr, "ERROR: jco_list in func lst_find: lstObj is NULL!\n"); 838 | return NULL; 839 | } else if (elem == NULL){ 840 | fprintf(stderr, "ERROR: jco_list in func lst_find: elem is NULL!\n"); 841 | return NULL; 842 | } else if ( ptr_to_funct_cmp == NULL ){ 843 | fprintf(stderr, 844 | "ERROR: jco_list in func lst_find: pointer to function compare is NULL !\n"); 845 | return NULL; 846 | } else if ( direction != LST_D_UP && direction != LST_D_DOWN ){ 847 | fprintf(stderr, 848 | "ERROR: jco_list in func lst_find: direction parameter isn't vallid!\n"); 849 | return NULL; 850 | } else { 851 | // NODE * currNode = NULL; 852 | 853 | if (lstObj->firstNode == NULL){ 854 | return NULL; 855 | if (foundNode != NULL) 856 | *foundNode = NULL; 857 | } 858 | if (direction == LST_D_UP){ 859 | if (currNode == NULL) 860 | currNode = lstObj->firstNode; 861 | while(currNode != NULL){ 862 | void * a = elem; 863 | void * b = currNode->elem; 864 | int cmp_val = (* ptr_to_funct_cmp) (a, b); 865 | if(cmp_val == 0){ 866 | if (foundNode != NULL) 867 | *foundNode = currNode; 868 | return currNode->elem; 869 | } else { 870 | // Search for next node and compare again for equality. 871 | currNode = currNode->next; 872 | } 873 | } 874 | if (foundNode != NULL) 875 | *foundNode = NULL; 876 | return NULL; 877 | 878 | }else if (direction == LST_D_DOWN){ 879 | if (currNode == NULL) 880 | currNode = lstObj->lastNode; 881 | while(currNode != NULL){ 882 | void * a = elem; 883 | void * b = currNode->elem; 884 | int cmp_val = (* ptr_to_funct_cmp) (a, b); 885 | if(cmp_val == 0){ 886 | if (foundNode != NULL) 887 | *foundNode = currNode; 888 | return currNode->elem; 889 | } else { 890 | // Search for prev node and compare again for equality. 891 | currNode = currNode->prev; 892 | } 893 | } 894 | if (foundNode != NULL) 895 | *foundNode = NULL; 896 | return NULL; 897 | } 898 | } 899 | if (foundNode != NULL) 900 | *foundNode = NULL; 901 | return NULL; 902 | } 903 | 904 | -------------------------------------------------------------------------------- /utils/jco_list.h: -------------------------------------------------------------------------------- 1 | /******************************************************************* 2 | * Name: Abstract Double Linked List - jco_list.h and jco_list.c * 3 | * Author: Joao Nuno Carvalho * 4 | * Date: 2020.07.26 * 5 | * License: MIT Open Source Licence * 6 | * Files: jco_list.h * 7 | * jco_list.c * 8 | * main.c (Test and example of usage code) * 9 | ******************************************************************** 10 | * Notes: Read the main.c for examples on usage of this * 11 | * Abstract Double Linked List. * 12 | *******************************************************************/ 13 | 14 | #ifndef JCO_LIST_H 15 | #define JCO_LIST_H 16 | 17 | #include 18 | 19 | 20 | #define toi (int *) 21 | #define tof (float *) 22 | #define tod (double *) 23 | #define toc (char *) 24 | #define tob (bool *) 25 | 26 | typedef enum { LST_D_UP, LST_D_DOWN } LST_DIRECTION; 27 | // typedef enum { LST_Q_ONE, LST_Q_ALL } LST_QUANT; 28 | 29 | 30 | typedef struct node{ 31 | void * elem; 32 | struct node * next; 33 | struct node * prev; 34 | } NODE; 35 | 36 | typedef struct{ 37 | NODE * firstNode; 38 | NODE * lastNode; 39 | int size; 40 | NODE * iterator; 41 | } LST; 42 | 43 | 44 | int cmp_int(void * aIn, void * bIn); 45 | int cmp_float(void * aIn, void * bIn); 46 | int cmp_double(void * aIn, void * bIn); 47 | int cmp_single_char(void * aIn, void * bIn); 48 | int cmp_null_term_str(void * aIn, void * bIn); 49 | 50 | 51 | LST * lst_new(/* NULL or pointer to function equals == */); 52 | bool lst_free(LST * lstObj); 53 | 54 | int lst_size(LST * lstObj); 55 | 56 | void * lst_get_first(LST * lstObj); 57 | void * lst_get_last(LST * lstObj); 58 | void * lst_get_at(LST * lstObj, int pos); 59 | 60 | // Returns the previous existing element in that pos. 61 | void * lst_set(LST * lstObj, void * elem, int pos); 62 | 63 | bool lst_insert_first(LST * lstObj, void * elem); 64 | bool lst_insert_last(LST * lstObj, void * elem); 65 | bool lst_insert_at(LST * lstObj, void * elem, int pos); 66 | 67 | // Receives a pointer to a function compare that as 68 | // 2 parameters "a" and "b" and returns int, 69 | // 1 if a > b, 0 if a == b and -1 if a < b. 70 | bool lst_insert_ordered(LST * lstObj, void * elem, 71 | int (* const ptr_to_funct_cmp) (void * a, void * b ) ); 72 | 73 | void * lst_remove_first(LST * lstObj); 74 | void * lst_remove_last(LST * lstObj); 75 | void * lst_remove_at(LST * lstObj, int pos); 76 | 77 | // Iterators NEXT and PREV. 78 | bool lst_iter_get_first(LST * lstObj); 79 | bool lst_iter_get_last(LST * lstObj); 80 | void * lst_iter_next(LST * lstObj); 81 | void * lst_iter_prev(LST * lstObj); 82 | bool lst_iter_is_begin(LST * lstObj); 83 | bool lst_iter_is_end(LST * lstObj); 84 | 85 | void * lst_find(LST * lstObj, void * elem, 86 | int (* const ptr_to_funct_cmp) (void * a, void * b), 87 | LST_DIRECTION direction, 88 | NODE * currNode, 89 | NODE ** foundNode); 90 | 91 | 92 | // Stack 93 | // 94 | // Queue FIFO - First In First Out 95 | // 96 | // Queue LIFO - Last In First Out 97 | // 98 | 99 | 100 | ////////// 101 | // Not yet implemented... 102 | 103 | void lst_sort(LST * lstObj /*, pointer to function compare > */ ); 104 | // Not used in lists, used in arrayLists. 105 | void * lst_binary_search(LST * lstObj, void * elem /*, pointer to function equals == */ ); 106 | 107 | ////////// 108 | // The following 3 function can be made with the function lst_find() 109 | void * lst_find_first(LST * lstObj, void * elem, int (* const ptr_to_funct_equals) (void * a, void * b) ); 110 | void * lst_find_last(LST * lstObj, void * elem, int (* const ptr_to_funct_equals) (void * a, void * b) ); 111 | void * lst_find_all(LST * lstObj, void * elem, int (* const ptr_to_funct_equals) (void * a, void * b) ); 112 | 113 | 114 | #endif 115 | -------------------------------------------------------------------------------- /utils/main.c: -------------------------------------------------------------------------------- 1 | /******************************************************************* 2 | * Name: Abstract Double Linked List - jco_list.h and jco_list.c * 3 | * Author: Joao Nuno Carvalho * 4 | * Date: 2020.07.26 * 5 | * License: MIT Open Source Licence * 6 | * Files: jco_list.h * 7 | * jco_list.c * 8 | * main.c (Test and example of usage code) * 9 | ******************************************************************** 10 | * Notes: Read the main.c for examples on usage of this * 11 | * Abstract Double Linked List. * 12 | *******************************************************************/ 13 | 14 | #include 15 | #include 16 | #include 17 | #include "jco_list.h" 18 | 19 | 20 | int test_lst_01(){ 21 | char * testName = "test_lst_01"; 22 | printf("\n=>Starting %s...\n", testName); 23 | int numErrors = 0; 24 | bool resB = false; 25 | LST * lst = lst_new(); 26 | if (lst == NULL){ 27 | numErrors++; 28 | printf("TEST_ERROR %d: lst_new() returned a NULL pointer!\n", numErrors); 29 | } 30 | 31 | int numElem = lst_size(lst); 32 | if (numElem != 0){ 33 | numErrors++; 34 | printf("TEST_ERROR %d: lst_size() returned %d and should be 0 elements!\n", 35 | numErrors, numElem); 36 | } 37 | 38 | int * var_int_0 = (int *) malloc(sizeof(int)); 39 | int * var_int_1 = (int *) malloc(sizeof(int)); 40 | int * var_int_2 = (int *) malloc(sizeof(int)); 41 | int * var_int_3 = (int *) malloc(sizeof(int)); 42 | *var_int_0 = 10; 43 | *var_int_1 = 11; 44 | *var_int_2 = 12; 45 | *var_int_3 = 13; 46 | 47 | 48 | //////// 49 | // Insert elements. 50 | 51 | // Insert elem in final pos num 1. (empty list) 52 | int pos = 0; 53 | resB = lst_insert_at(lst, var_int_1, pos); 54 | if (!resB){ 55 | numErrors++; 56 | printf("TEST_ERROR %d: lst_insert_at() returned a false!\n", numErrors); 57 | } 58 | // Insert elem in final pos num 0. ( not empty list) 59 | pos = 0; 60 | resB = lst_insert_at(lst, var_int_0, pos); 61 | if (!resB){ 62 | numErrors++; 63 | printf("TEST_ERROR %d: lst_insert_at() returned a false!\n", numErrors); 64 | } 65 | // Insert elem in final pos num 3. (last) 66 | pos = 2; 67 | resB = lst_insert_at(lst, var_int_3, pos); 68 | if (!resB){ 69 | numErrors++; 70 | printf("TEST_ERROR %d: lst_insert_at() returned a false!\n", numErrors); 71 | } 72 | pos = 2; 73 | // Insert elem in final pos num 2. (middle) 74 | resB = lst_insert_at(lst, var_int_2, pos); 75 | if (!resB){ 76 | numErrors++; 77 | printf("TEST_ERROR %d: lst_insert_at() returned a false!\n", numErrors); 78 | } 79 | 80 | ////// 81 | // Iterators 82 | 83 | printf(" GET AT lst list values:\n"); 84 | for(int i=0; iStarting %s...\n", testName); 200 | int numErrors = 0; 201 | bool resB = false; 202 | LST * lst = lst_new(); 203 | 204 | int numElem = lst_size(lst); 205 | 206 | int * var_int_0 = (int *) malloc(sizeof(int)); 207 | int * var_int_1 = (int *) malloc(sizeof(int)); 208 | int * var_int_2 = (int *) malloc(sizeof(int)); 209 | int * var_int_3 = (int *) malloc(sizeof(int)); 210 | *var_int_0 = 10; 211 | *var_int_1 = 11; 212 | *var_int_2 = 12; 213 | *var_int_3 = 13; 214 | 215 | //////// 216 | // Insert elements. 217 | 218 | // Insert ordered elem in final pos num 1. (empty list) 219 | resB = lst_insert_ordered(lst, var_int_1, cmp_int); 220 | 221 | // Insert ordered elem in final pos num 0. ( not empty list) 222 | resB = lst_insert_ordered(lst, var_int_0, cmp_int); 223 | 224 | // Insert ordered elem in final pos num 3. (last) 225 | resB = lst_insert_ordered(lst, var_int_3, cmp_int); 226 | 227 | // Insert ordered elem in final pos num 2. (middle) 228 | resB = lst_insert_ordered(lst, var_int_2, cmp_int); 229 | 230 | 231 | ////// 232 | // Iterators 233 | 234 | printf(" Iterator NEXT lst list values:\n"); 235 | bool iterOK = lst_iter_get_first( lst ); 236 | while( !lst_iter_is_end( lst ) ){ 237 | int * pTmpI = (int *) lst_iter_next( lst ); 238 | if (pTmpI != NULL) 239 | printf("%d\n", *pTmpI); 240 | } 241 | 242 | 243 | ///////// 244 | // Test lst_find 245 | 246 | NODE * currNode = NULL; 247 | NODE ** foundNode = (NODE **) calloc(1, sizeof(NODE *)); 248 | 249 | int * var_int_n = (int * ) malloc(sizeof(int)); 250 | *var_int_n = 33; 251 | const int NUM_PTRS = 5; 252 | int * ptrArInt[5] = {var_int_0, var_int_1, var_int_2, var_int_3, var_int_n}; 253 | 254 | for(int i = 0; i < NUM_PTRS; ++i){ 255 | if (foundNode == NULL) 256 | printf("ERROR: While allocating NODE ** foundNode.\n"); 257 | int * var_tmp = ptrArInt[i]; 258 | int * pInt_n = (int *) lst_find(lst, var_tmp, cmp_int, LST_D_UP, 259 | NULL, NULL); 260 | // currNode, foundNode); 261 | if (pInt_n == NULL) 262 | printf("TEST_ERROR %d: lst_find() returned NULL error or not found!\n", numErrors); 263 | else 264 | printf("Found value %d\n", *pInt_n); 265 | } 266 | 267 | 268 | ///////// 269 | // Test lst_find() detecting several occurrences of element inside an object. 270 | 271 | // Insert one more element, copy of var_int_0. 272 | *var_int_n = *var_int_0; 273 | lst_insert_last(lst, var_int_n); 274 | printf(" Value %d added to the end of the list, repeated two times.\n", *var_int_n); 275 | 276 | 277 | int * pInt_n_1 = (int *) lst_find(lst, var_int_0, cmp_int, LST_D_UP, 278 | currNode, foundNode); 279 | printf("Found in sequence value %d\n", *pInt_n_1); 280 | 281 | // Dereference the pointer to pointer to Node and advances to the NEXT. 282 | currNode = (*foundNode)->next; 283 | // foundNode = NULL; 284 | int * pInt_n_2 = (int *) lst_find(lst, var_int_0, cmp_int, LST_D_UP, 285 | currNode, foundNode); 286 | if (pInt_n_1 != pInt_n_2) 287 | printf(" Correct - Pointer pInt_n_1 != pInt_n_2 - %p != %p \n", pInt_n_1, pInt_n_2); 288 | 289 | printf("Found in sequence value %d\n", *pInt_n_2); 290 | 291 | free(foundNode); 292 | free(var_int_n); 293 | 294 | lst_remove_last(lst); 295 | 296 | /////////// 297 | // Test SET 298 | 299 | int * var_int_10 = (int *) malloc(sizeof(int)); 300 | int * var_int_11 = (int *) malloc(sizeof(int)); 301 | int * var_int_12 = (int *) malloc(sizeof(int)); 302 | int * var_int_13 = (int *) malloc(sizeof(int)); 303 | *var_int_10 = 20; 304 | *var_int_11 = 21; 305 | *var_int_12 = 22; 306 | *var_int_13 = 23; 307 | 308 | int pos = 0; 309 | int * p_tmp_old = (int *) lst_set(lst, var_int_10, pos); 310 | if (p_tmp_old == NULL || *p_tmp_old != *var_int_0){ 311 | numErrors++; 312 | printf("TEST_ERROR %d: lst_set() returned NULL or int value is different!\n", 313 | numErrors); 314 | } 315 | free(p_tmp_old); 316 | 317 | pos = 1; 318 | p_tmp_old = (int *) lst_set(lst, var_int_11, pos); 319 | if (p_tmp_old == NULL || *p_tmp_old != *var_int_1){ 320 | numErrors++; 321 | printf("TEST_ERROR %d: lst_set() returned NULL or int value is different!\n", 322 | numErrors); 323 | } 324 | free(p_tmp_old); 325 | 326 | pos = 2; 327 | p_tmp_old = (int *) lst_set(lst, var_int_12, pos); 328 | if (p_tmp_old == NULL || *p_tmp_old != *var_int_2){ 329 | numErrors++; 330 | printf("TEST_ERROR %d: lst_set() returned NULL or int value is different!\n", 331 | numErrors); 332 | } 333 | free(p_tmp_old); 334 | 335 | pos = 3; 336 | p_tmp_old = (int *) lst_set(lst, var_int_13, pos); 337 | if (p_tmp_old == NULL || *p_tmp_old != *var_int_3){ 338 | numErrors++; 339 | printf("TEST_ERROR %d: lst_set() returned NULL or int value is different!\n", 340 | numErrors); 341 | } 342 | free(p_tmp_old); 343 | 344 | 345 | ////// 346 | // Iterators 347 | 348 | printf("After lst_set() - Iterator NEXT lst list values:\n"); 349 | iterOK = lst_iter_get_first( lst ); 350 | while( !lst_iter_is_end( lst ) ){ 351 | int * pTmpI = (int *) lst_iter_next( lst ); 352 | if (pTmpI != NULL) 353 | printf("%d\n", *pTmpI); 354 | } 355 | 356 | 357 | //////// 358 | // Remove elements. 359 | 360 | // Remove element 1, in the middle. 361 | pos = 1; 362 | int * pInt_0 = (int *) lst_remove_at(lst, pos); 363 | if (pInt_0 == NULL){ 364 | numErrors++; 365 | printf("TEST_ERROR %d: lst_remove_at() returned NULL!\n", numErrors); 366 | } 367 | // Remove element 1, in the last pos. 368 | pos = 1; 369 | int * pInt_1 = (int *) lst_remove_at(lst, pos); 370 | if (pInt_1 == NULL){ 371 | numErrors++; 372 | printf("TEST_ERROR %d: lst_remove_at() returned NULL!\n", numErrors); 373 | } 374 | // Remove element 0, in the first pos. 375 | pos = 0; 376 | int * pInt_2 = (int *) lst_remove_at(lst, pos); 377 | if (pInt_2 == NULL){ 378 | numErrors++; 379 | printf("TEST_ERROR %d: lst_remove_at() returned NULL!\n", numErrors); 380 | } 381 | // Remove element 0, in the first pos. 382 | pos = 0; 383 | int * pInt_3 = (int *) lst_remove_at(lst, pos); 384 | if (pInt_3 == NULL){ 385 | numErrors++; 386 | printf("TEST_ERROR %d: lst_remove_at() returned NULL!\n", numErrors); 387 | } 388 | 389 | // Free the block of memory that the pointer points to objects or structures. 390 | free(pInt_0); 391 | free(pInt_1); 392 | free(pInt_2); 393 | free(pInt_3); 394 | 395 | fflush(stdout); 396 | 397 | resB = lst_free(lst); 398 | if (!resB){ 399 | numErrors++; 400 | printf("TEST_ERROR %d: lst_free() returned a false!\n", numErrors); 401 | } 402 | if (numErrors == 0) 403 | printf(" %s Passed.\n", testName); 404 | else 405 | printf(" %s Failed.\n", testName); 406 | return numErrors; 407 | } 408 | 409 | 410 | int main(){ 411 | printf("\nTest program start....!\n"); 412 | 413 | // stderr = stdout; 414 | 415 | // Test 1 416 | test_lst_01(); 417 | 418 | // Test 2 419 | test_lst_02(); 420 | 421 | } -------------------------------------------------------------------------------- /utils/makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -O2 -std=c11 -Wall -Werror 3 | RM = rm -f 4 | 5 | CFLAGS = -g -std=c11 -Wall 6 | 7 | default: all 8 | 9 | all: list_test 10 | 11 | jco_list.o: jco_list.c 12 | $(CC) $(CFLAGS) -o jco_list.o jco_list.c 13 | 14 | main.o: main.c 15 | $(CC) $(CFLAGS) -o main.o main.c 16 | 17 | list_test: main.c jco_list.c 18 | $(CC) $(CFLAGS) -o list_test main.c jco_list.c 19 | 20 | clean: 21 | $(RM) list_test 22 | $(RM) main.o 23 | $(RM) jco_list.o --------------------------------------------------------------------------------