├── .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
--------------------------------------------------------------------------------