CMPUT201W20B2 Week 8
Table of Contents
1 Week8
1.1 Copyright Statement
If you are in CMPUT201 at UAlberta this code is released in the public domain to you.
Otherwise it is (c) 2020 Abram Hindle, Hazel Campbell AGPL3.0+
1.1.1 License
Week 3 notes Copyright (C) 2020 Abram Hindle, Hazel Campbell
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along with this program. If not, see https://www.gnu.org/licenses/.
1.1.2 Hazel Code is licensed under AGPL3.0+
Hazel's code is also found here https://github.com/hazelybell/examples/tree/C-2020-01
Hazel code is licensed: The example code is licensed under the AGPL3+ license, unless otherwise noted.
1.2 Init ORG-MODE
;; I need this for org-mode to work well ;; If we have a new org-mode use ob-shell ;; otherwise use ob-sh --- but not both! (if (require 'ob-shell nil 'noerror) (progn (org-babel-do-load-languages 'org-babel-load-languages '((shell . t)))) (progn (require 'ob-sh) (org-babel-do-load-languages 'org-babel-load-languages '((sh . t))))) (org-babel-do-load-languages 'org-babel-load-languages '((C . t))) (org-babel-do-load-languages 'org-babel-load-languages '((python . t))) (setq org-src-fontify-natively t) (setq org-confirm-babel-evaluate nil) ;; danger! (custom-set-faces '(org-block ((t (:inherit shadow :foreground "black")))))
1.2.1 Org export
(org-html-export-to-html) (org-latex-export-to-pdf) (org-ascii-export-to-ascii)
1.3 Org Template
Copy and paste this to demo C
#include <stdio.h> int main(int argc, char**argv) { return 0; }
1.4 Remember how to compile?
gcc -std=c99 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o programname programname.c
1.5 Malloc continued!
Continued.
1.5.1 free
What happens if we don't free?
Our program can get bigger!
#include <assert.h> #include <stdio.h> #include <stdlib.h> #include <string.h> int * testAllocArray(int arrLen) { int* array = calloc( sizeof(int), arrLen ); assert(array!=NULL); for(int idx=0; idx<arrLen; idx++) { array[idx] = idx; } return array; } int main() { for (int i = 1; i < 10000000; i+=1*1024*1024) { int * bigArray = testAllocArray( i ); printf("%u ints allocated!\n",1+bigArray[i-1]); printf("%lu bytes!\n", sizeof(int)*i); // free(bigArray); // remember to free it when done! } }
1 ints allocated! 4 bytes! 1048577 ints allocated! 4194308 bytes! 2097153 ints allocated! 8388612 bytes! 3145729 ints allocated! 12582916 bytes! 4194305 ints allocated! 16777220 bytes! 5242881 ints allocated! 20971524 bytes! 6291457 ints allocated! 25165828 bytes! 7340033 ints allocated! 29360132 bytes! 8388609 ints allocated! 33554436 bytes! 9437185 ints allocated! 37748740 bytes!
Valgrind is a memory leak detector. It analyzes memory allocations and warns us about mistakes.
Valgrind will show us that we're leaking memory (losing track of it and not freeing it).
gcc -std=c99 -Wall -pedantic -Werror -o nofree ./nofree.c valgrind ./nofree 2>&1 echo now let\'s leak check valgrind --leak-check=full ./nofree 2>&1
==28799== Memcheck, a memory error detector ==28799== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==28799== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info ==28799== Command: ./nofree ==28799== 1 ints allocated! 4 bytes! 1048577 ints allocated! 4194308 bytes! 2097153 ints allocated! 8388612 bytes! 3145729 ints allocated! 12582916 bytes! 4194305 ints allocated! 16777220 bytes! 5242881 ints allocated! 20971524 bytes! 6291457 ints allocated! 25165828 bytes! 7340033 ints allocated! 29360132 bytes! 8388609 ints allocated! 33554436 bytes! 9437185 ints allocated! 37748740 bytes! ==28799== ==28799== HEAP SUMMARY: ==28799== in use at exit: 188,743,720 bytes in 10 blocks ==28799== total heap usage: 11 allocs, 1 frees, 188,747,816 bytes allocated ==28799== ==28799== LEAK SUMMARY: ==28799== definitely lost: 100,663,320 bytes in 6 blocks ==28799== indirectly lost: 0 bytes in 0 blocks ==28799== possibly lost: 88,080,400 bytes in 4 blocks ==28799== still reachable: 0 bytes in 0 blocks ==28799== suppressed: 0 bytes in 0 blocks ==28799== Rerun with --leak-check=full to see details of leaked memory ==28799== ==28799== For counts of detected and suppressed errors, rerun with: -v ==28799== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) now let's leak check ==28801== Memcheck, a memory error detector ==28801== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==28801== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info ==28801== Command: ./nofree ==28801== 1 ints allocated! 4 bytes! 1048577 ints allocated! 4194308 bytes! 2097153 ints allocated! 8388612 bytes! 3145729 ints allocated! 12582916 bytes! 4194305 ints allocated! 16777220 bytes! 5242881 ints allocated! 20971524 bytes! 6291457 ints allocated! 25165828 bytes! 7340033 ints allocated! 29360132 bytes! 8388609 ints allocated! 33554436 bytes! 9437185 ints allocated! 37748740 bytes! ==28801== ==28801== HEAP SUMMARY: ==28801== in use at exit: 188,743,720 bytes in 10 blocks ==28801== total heap usage: 11 allocs, 1 frees, 188,747,816 bytes allocated ==28801== ==28801== 88,080,400 bytes in 4 blocks are possibly lost in loss record 1 of 2 ==28801== at 0x4C31B25: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==28801== by 0x1086F6: testAllocArray (in /home/hindle1/projects/CMPUT201W20/2020-01/CMPUT201W20B2-public/week07/nofree) ==28801== by 0x10876F: main (in /home/hindle1/projects/CMPUT201W20/2020-01/CMPUT201W20B2-public/week07/nofree) ==28801== ==28801== 100,663,320 bytes in 6 blocks are definitely lost in loss record 2 of 2 ==28801== at 0x4C31B25: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==28801== by 0x1086F6: testAllocArray (in /home/hindle1/projects/CMPUT201W20/2020-01/CMPUT201W20B2-public/week07/nofree) ==28801== by 0x10876F: main (in /home/hindle1/projects/CMPUT201W20/2020-01/CMPUT201W20B2-public/week07/nofree) ==28801== ==28801== LEAK SUMMARY: ==28801== definitely lost: 100,663,320 bytes in 6 blocks ==28801== indirectly lost: 0 bytes in 0 blocks ==28801== possibly lost: 88,080,400 bytes in 4 blocks ==28801== still reachable: 0 bytes in 0 blocks ==28801== suppressed: 0 bytes in 0 blocks ==28801== ==28801== For counts of detected and suppressed errors, rerun with: -v ==28801== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
1.5.2 Malloc and structs
Mallocs are often used with arrays of structs. You need to get the sizeof the struct.
#include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <time.h> enum card_face { ACE = 1, FACE2, FACE3, FACE4, FACE5, FACE6, FACE7, FACE8, FACE9, FACE10, JACK, QUEEN, KING, }; typedef enum card_face CardFace; #define NFACES 13 #define NFACEOFF 1 enum card_suit { CLUBS, HEARTS, DIAMONDS, SPADES }; typedef enum card_suit CardSuit; #define NSUIT 4 struct playing_card { CardFace face; CardSuit suit; }; typedef struct playing_card PlayingCard; #define HANDSIZE 5 bool isFlush(PlayingCard hand[HANDSIZE]) { CardSuit suit = hand[0].suit; for (int i = 1; i < HANDSIZE; i++ ) { if (suit != hand[i].suit) { return false; } } return true; } PlayingCard randomCard() { PlayingCard card = {ACE, CLUBS}; card.face = NFACEOFF + ( rand() % NFACES ); card.suit = rand() % NSUIT; return card; } int main() { srand(time(NULL)); const int N = 1000000; PlayingCard * bigHand = malloc(sizeof(PlayingCard)*N); for (int i = 0; i < N; i++) { bigHand[i] = randomCard(); } int flushes = 0; for (int i = 0; i < N - HANDSIZE; i+=HANDSIZE) { if (isFlush(bigHand + i)) { if (flushes < 10) { // reduce printing printf("Flush found at card %d\n", i); printf("Suit %d\n", bigHand[i].suit); } flushes++; } } printf("We found %d flushes out of %d hands: %f\n", flushes, N/HANDSIZE, flushes/(float)(N/HANDSIZE)); }
Flush found at card 225 Suit 2 Flush found at card 1370 Suit 1 Flush found at card 4095 Suit 1 Flush found at card 8160 Suit 1 Flush found at card 8665 Suit 0 Flush found at card 10025 Suit 1 Flush found at card 12900 Suit 0 Flush found at card 13085 Suit 0 Flush found at card 14855 Suit 3 Flush found at card 15145 Suit 2 We found 799 flushes out of 200000 hands: 0.003995
1.5.3 Malloc Array of Array versus 2D
So instead of allocating a big block and carving a 2D array out of it we could just allocate each row and make an array of arrays.
Try playing with the order of allocation of rows. Does it affect the result?
#include <stdio.h> #include <stdlib.h> // This example compares using malloc to get space for a 2-D array vs using malloc to make space for a array of arrays. int * alloc2d(size_t n) { // we can just do 1 malloc() return (int *) malloc(n * n * sizeof(int)); } int ** alloc_aoa(size_t n) { // we have to do 1 + n malloc()s int ** p = malloc(n * sizeof(int *)); // we don't need to do them in order... for (size_t i = 0; i < n; i++) { p[i] = malloc(n * sizeof(int)); } return p; } void free2d(int * p) { // we can just do 1 free() free(p); } void free_aoa(size_t n, int ** p) { // we have to do n + 1 free()s for (size_t i = 0; i < n; i++) { free(p[i]); } free(p); } int get2d(size_t n, int * p, size_t i, size_t j) { return p[i * n + j]; } int get_aoa(int **p, size_t i, size_t j) { return p[i][j]; } int set2d(size_t n, int * p, size_t i, size_t j, int v) { return p[i * n + j] = v; } int set_aoa(int **p, size_t i, size_t j, int v) { return p[i][j] = v; } int main(int argc, char **argv) { srand(1); // printf("I'm going to make space for a big, square table in memory.\n"); // printf("How many rows and columns would you like to make space for? "); size_t n; // int r = scanf("%zu", &n); n = 30; if (n != 1) { printf("Sorry, I couldn't understand that :(\n"); exit(1); } // allocate them int *p2d = alloc2d(n); int **aoa = alloc_aoa(n); // initialize them for (size_t i = 0; i < n; i++) { for (size_t j = 0; j < n; j++) { set2d(n, p2d, i, j, rand() % 10); set_aoa(aoa, i, j, rand() % 10); } } // print them out printf("2d:\n"); for (size_t i = 0; i < n; i++) { for (size_t j = 0; j < n; j++) { int x = get2d(n, p2d, i, j); printf("%d ", x); } printf("\n"); } printf("aoa:\n"); for (size_t i = 0; i < n; i++) { for (size_t j = 0; j < n; j++) { int x = get_aoa(aoa, i, j); printf("%d ", x); } printf("\n"); } // free them free2d(p2d); free_aoa(n, aoa); }
I'm going to make space for a big, square table in memory. How many rows and columns would you like to make space for? Sorry, I couldn't understand that :( 2d: 3 7 3 6 9 2 0 3 0 2 1 7 2 2 7 9 2 9 3 1 9 1 4 8 5 3 1 6 2 6 5 4 6 6 3 4 2 4 4 3 7 6 8 3 4 2 6 9 6 4 5 4 7 7 7 2 1 6 5 4 0 1 7 1 9 7 7 6 6 9 8 2 3 0 8 0 6 8 6 1 9 4 1 3 4 4 7 3 7 9 2 7 5 4 8 9 5 8 3 8 6 3 3 6 4 8 9 7 4 0 0 2 4 5 4 9 2 7 5 8 2 9 6 0 1 5 1 8 0 4 2 8 2 4 2 0 2 9 8 3 1 3 0 9 9 9 3 0 6 4 0 6 6 5 9 7 8 9 6 2 6 3 1 9 1 9 0 5 7 4 0 2 6 0 2 2 5 2 0 8 8 4 9 9 2 4 9 3 0 0 9 3 1 4 1 6 4 2 4 2 8 2 8 6 3 3 3 0 7 8 0 8 9 3 3 3 6 2 5 7 6 4 0 8 0 6 4 9 9 8 0 7 9 5 9 5 4 9 5 3 7 8 9 7 2 3 9 2 1 6 1 0 3 1 0 6 7 0 4 4 5 2 0 6 6 8 6 7 1 1 7 2 4 2 2 0 9 5 0 7 8 0 6 6 9 5 7 5 3 3 9 7 7 1 0 8 5 4 7 3 0 7 9 2 3 1 2 2 7 1 4 7 1 7 4 8 1 6 1 6 8 8 0 2 7 6 6 7 7 9 7 6 8 3 4 5 1 5 9 3 5 2 7 3 6 6 3 4 9 2 8 0 4 6 7 3 3 5 0 7 3 0 0 1 3 9 4 5 8 5 5 9 7 3 6 5 6 0 1 2 9 0 2 4 3 8 3 0 3 9 7 2 2 4 8 0 9 2 1 3 2 4 1 5 1 9 1 3 7 8 7 4 4 1 8 2 9 6 6 9 0 9 1 8 6 7 7 2 1 0 0 0 3 4 1 0 2 7 6 4 2 7 4 6 7 5 2 3 4 9 2 1 3 2 5 5 0 4 6 2 8 5 6 8 7 2 0 8 5 7 8 3 7 7 9 1 0 9 8 3 0 9 1 7 7 2 1 8 4 6 6 4 8 8 5 4 0 7 2 2 3 9 1 5 4 2 1 2 2 9 4 5 1 0 1 7 9 1 7 0 0 5 9 1 1 0 8 4 2 4 9 2 9 0 4 9 5 6 3 9 2 3 9 1 4 8 7 3 9 5 8 0 3 1 7 5 1 3 0 5 2 9 9 9 1 3 3 4 1 6 7 2 2 1 4 8 3 7 3 2 3 6 1 6 0 5 5 9 8 2 9 1 0 6 9 8 8 3 0 5 3 8 1 9 0 5 4 4 9 9 3 3 7 4 9 9 2 6 9 6 1 3 2 3 9 4 4 9 8 2 5 3 4 5 7 9 7 7 9 5 4 7 3 2 2 3 1 8 0 2 9 9 3 8 6 7 7 1 0 4 3 3 7 1 9 6 9 5 1 9 1 2 0 3 1 7 8 0 4 3 9 4 5 2 7 8 9 3 8 4 6 8 5 1 6 8 6 5 6 1 3 5 6 4 6 7 3 9 0 2 9 3 5 7 7 6 4 3 2 6 9 5 3 4 1 1 9 5 2 9 7 4 1 1 8 4 3 3 7 3 8 0 8 8 3 5 5 2 8 2 3 7 7 6 2 7 3 2 5 7 9 1 4 5 8 3 5 1 5 0 8 9 9 6 5 5 0 2 9 2 6 5 8 7 6 2 9 0 7 5 4 0 8 4 4 8 2 6 2 7 4 6 4 4 5 6 3 7 2 0 9 1 4 5 2 0 3 1 5 4 0 3 9 4 3 2 5 8 1 1 8 3 9 5 4 6 2 0 3 7 3 1 4 1 6 3 7 0 4 3 7 9 3 2 9 5 0 3 9 5 3 2 7 7 0 6 5 8 9 7 0 1 3 7 2 1 3 8 8 8 8 9 3 4 7 3 6 2 2 5 4 4 1 3 8 3 9 4 1 0 aoa: 6 5 5 2 1 7 9 6 6 6 8 9 0 3 5 2 8 7 6 2 3 9 7 4 0 6 0 3 0 1 5 7 5 9 7 5 5 7 4 0 8 8 4 1 9 0 8 2 6 9 0 8 1 2 2 6 0 1 9 9 9 7 1 5 7 6 3 5 3 4 1 9 9 8 5 9 3 5 1 5 8 8 0 0 4 4 6 1 5 6 1 8 7 1 5 7 3 8 1 9 4 3 8 0 8 8 7 6 3 3 9 5 0 9 6 2 4 7 4 1 8 3 8 2 0 1 0 5 6 6 5 6 8 7 4 6 9 0 1 1 0 4 3 1 6 3 8 5 6 0 4 2 7 6 8 2 2 9 0 7 1 2 5 9 4 1 7 8 0 8 4 9 1 4 2 0 5 9 2 3 0 0 1 6 5 4 9 6 5 2 4 5 7 3 4 9 2 6 1 8 9 8 8 8 8 3 8 4 6 9 6 7 0 3 7 2 5 6 8 9 0 1 4 7 8 2 7 3 2 3 1 8 1 4 2 7 9 4 9 5 0 1 9 8 5 4 0 0 9 2 2 7 1 9 5 7 4 6 7 8 8 6 6 4 2 9 0 0 0 3 7 6 5 0 9 9 4 1 3 8 6 4 7 0 7 9 8 3 8 7 3 8 4 9 9 8 8 3 1 8 9 9 3 4 7 2 0 1 5 7 1 1 1 0 0 5 6 2 9 4 0 1 2 9 5 4 3 9 4 1 0 0 5 9 1 4 5 4 8 8 2 2 0 4 3 3 4 3 7 5 9 2 7 5 1 3 8 1 8 6 5 8 4 1 5 3 1 0 3 6 9 0 6 7 1 0 5 8 2 6 1 4 7 0 2 0 7 0 4 2 4 5 4 3 6 8 2 3 8 4 2 5 7 7 6 8 3 3 9 6 0 8 8 6 5 1 9 0 4 9 8 3 4 9 7 3 1 2 5 9 4 1 7 1 3 3 1 5 5 2 1 2 1 5 8 9 7 6 7 7 2 6 0 1 6 0 3 6 0 5 9 0 0 3 8 1 5 5 0 3 2 0 7 6 1 9 8 8 0 7 6 2 7 9 6 7 5 8 5 5 8 8 3 7 2 5 5 3 7 1 4 4 9 7 1 2 6 0 2 7 3 6 4 3 2 7 8 0 6 1 2 1 7 3 2 6 7 9 4 5 1 8 6 6 0 4 4 6 9 5 1 0 9 3 5 5 3 8 5 3 6 3 6 8 0 1 0 0 4 4 4 9 4 8 6 9 3 6 5 1 2 9 8 2 7 6 7 2 7 5 7 8 3 4 3 8 0 9 0 4 0 2 0 3 0 3 7 1 0 0 1 0 7 1 3 9 8 6 2 0 0 3 9 9 1 4 0 5 5 1 4 7 7 3 2 4 9 3 3 9 4 9 9 5 3 0 2 2 0 0 1 9 6 1 5 9 8 7 5 7 1 6 6 4 6 2 4 0 6 4 7 4 2 7 5 8 5 2 5 9 6 1 5 2 9 6 2 6 3 6 0 8 1 9 3 0 2 1 7 1 3 5 0 2 4 5 2 2 9 3 1 2 9 4 0 4 7 0 2 6 0 5 8 1 0 0 1 0 9 0 3 4 6 3 9 0 4 6 5 1 7 1 9 3 7 9 1 8 9 8 4 0 6 2 8 0 9 6 5 8 6 8 2 6 9 0 7 3 1 8 4 6 3 4 7 3 0 4 7 7 9 3 4 4 5 6 6 6 9 9 5 3 6 3 0 6 3 8 6 2 0 6 5 9 6 3 3 2 4 0 9 5 6 2 1 1 7 1 1 8 0 3 8 8 2 6 6 0 7 2 0 3 0 3 4 4 3 1 3 5 1 3 7 4 9 7 1 1 7 6 9 0 1 8 4 4 7 7 5 0 2 9 0 7 9 2 8 5 6 6 0 0 4 3 1 7 7 8 0 8 3 0 6 3 2 5 3 2 5 0 6 3 7 3 1 9 4 0 9 7 6 9 2 1 1 8 2 5 0 1
1.5.4 Malloc array of arrays structs?
Arrays of Arrays? Pointers?
X ** x?
#include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <time.h> enum card_face { ACE = 1, FACE2, FACE3, FACE4, FACE5, FACE6, FACE7, FACE8, FACE9, FACE10, JACK, QUEEN, KING, }; typedef enum card_face CardFace; #define NFACES 13 #define NFACEOFF 1 enum card_suit { CLUBS, HEARTS, DIAMONDS, SPADES }; typedef enum card_suit CardSuit; #define NSUIT 4 struct playing_card { CardFace face; CardSuit suit; }; typedef struct playing_card PlayingCard; #define HANDSIZE 5 bool isFlush(PlayingCard hand[HANDSIZE]) { CardSuit suit = hand[0].suit; for (int i = 1; i < HANDSIZE; i++ ) { if (suit != hand[i].suit) { return false; } } return true; } PlayingCard randomCard() { PlayingCard card = {ACE, CLUBS}; card.face = NFACEOFF + ( rand() % NFACES ); card.suit = rand() % NSUIT; return card; } int main() { srand(time(NULL)); const int HANDS = 1000000; PlayingCard * hands = malloc(sizeof(PlayingCard)*HANDS*HANDSIZE); for (int i = 0; i < HANDS*HANDSIZE; i++) { hands[i] = randomCard(); } int flushes = 0; for (int i = 0; i < HANDS; i++) { if (isFlush(hands + i*HANDSIZE)) { if (flushes < 10) { // reduce printing printf("Flush found at card %d\n", i); printf("Suit %d\n", hands[i].suit); } flushes++; } } printf("We found %d flushes out of %d hands: %f\n", flushes, HANDS, flushes/(float)(HANDS)); }
Flush found at card 19 Suit 3 Flush found at card 340 Suit 1 Flush found at card 450 Suit 0 Flush found at card 870 Suit 0 Flush found at card 918 Suit 1 Flush found at card 932 Suit 2 Flush found at card 970 Suit 2 Flush found at card 1375 Suit 0 Flush found at card 1438 Suit 3 Flush found at card 1631 Suit 2 We found 3902 flushes out of 1000000 hands: 0.003902
That's kind of gross, let's model our hands as arrays of 5 cards instead.
#include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <time.h> enum card_face { ACE = 1, FACE2, FACE3, FACE4, FACE5, FACE6, FACE7, FACE8, FACE9, FACE10, JACK, QUEEN, KING, }; typedef enum card_face CardFace; #define NFACES 13 #define NFACEOFF 1 enum card_suit { CLUBS, HEARTS, DIAMONDS, SPADES }; typedef enum card_suit CardSuit; #define NSUIT 4 struct playing_card { CardFace face; CardSuit suit; }; typedef struct playing_card PlayingCard; #define HANDSIZE 5 bool isFlush(PlayingCard hand[HANDSIZE]) { CardSuit suit = hand[0].suit; for (int i = 1; i < HANDSIZE; i++ ) { if (suit != hand[i].suit) { return false; } } return true; } PlayingCard randomCard() { PlayingCard card = {ACE, CLUBS}; card.face = NFACEOFF + ( rand() % NFACES ); card.suit = rand() % NSUIT; return card; } int main() { srand(time(NULL)); const int HANDS = 1000000; // Pointer to arrays PlayingCard (*hands)[5] = malloc(sizeof(PlayingCard[5])*HANDS); for (int i = 0; i < HANDS; i++) { for (int j = 0; j < HANDSIZE; j++) { hands[i][j] = randomCard(); } } int flushes = 0; for (int i = 0; i < HANDS; i++) { if (isFlush(hands[i])) { if (flushes < 10) { // reduce printing printf("Flush found at card %d\n", i); printf("Suit %d\n", hands[i][0].suit); } flushes++; } } printf("We found %d flushes out of %d hands: %f\n", flushes, HANDS, flushes/(float)(HANDS)); }
Flush found at card 223 Suit 0 Flush found at card 323 Suit 1 Flush found at card 335 Suit 3 Flush found at card 407 Suit 1 Flush found at card 896 Suit 3 Flush found at card 1027 Suit 3 Flush found at card 1124 Suit 0 Flush found at card 1279 Suit 0 Flush found at card 1301 Suit 0 Flush found at card 1734 Suit 3 We found 3855 flushes out of 1000000 hands: 0.003855
- Remember to tangle this to write to disk
#include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <time.h> #include <assert.h> enum card_face { ACE = 1, FACE2, FACE3, FACE4, FACE5, FACE6, FACE7, FACE8, FACE9, FACE10, JACK, QUEEN, KING, }; typedef enum card_face CardFace; #define NFACES 13 #define NFACEOFF 1 enum card_suit { CLUBS, HEARTS, DIAMONDS, SPADES }; typedef enum card_suit CardSuit; #define NSUIT 4 struct playing_card { CardFace face; CardSuit suit; }; typedef struct playing_card PlayingCard; #define HANDSIZE 5 bool isFlush(PlayingCard hand[HANDSIZE]) { CardSuit suit = hand[0].suit; for (int i = 1; i < HANDSIZE; i++ ) { if (suit != hand[i].suit) { return false; } } return true; } PlayingCard randomCard() { PlayingCard card = {ACE, CLUBS}; card.face = NFACEOFF + ( rand() % NFACES ); card.suit = rand() % NSUIT; return card; } PlayingCard * allocateHand() { PlayingCard * hand = malloc(sizeof(PlayingCard[HANDSIZE])); assert(hand!=NULL); return hand; } void randomizeHand( PlayingCard hand[HANDSIZE]) { for (int i = 0; i < HANDSIZE; i++) { hand[i] = randomCard(); } } int main() { srand(time(NULL)); const int HANDS = 1000000; // Pointer to arrays of arrays PlayingCard **hands = malloc(sizeof(PlayingCard(*)[5]) * HANDS); for (int i = HANDS-1; i >= 0; i--) { hands[i] = allocateHand(); randomizeHand( hands[i] ); } int flushes = 0; for (int i = 0; i < HANDS; i++) { if (isFlush(hands[i])) { if (flushes < 10) { // reduce printing printf("Flush found at card %d\n", i); printf("Suit %d\n", hands[i][0].suit); } flushes++; } } printf("We found %d flushes out of %d hands: %f\n", flushes, HANDS, flushes/(float)(HANDS)); for (int i = 0; i < HANDS; i++) { // comment these out to try valgrind free(hands[i]); } // comment these out to try valgrind free(hands); }
Flush found at card 148 Suit 0 Flush found at card 792 Suit 2 Flush found at card 845 Suit 1 Flush found at card 1055 Suit 1 Flush found at card 1152 Suit 3 Flush found at card 1240 Suit 0 Flush found at card 1259 Suit 3 Flush found at card 1873 Suit 1 Flush found at card 2368 Suit 0 Flush found at card 2509 Suit 0 We found 4003 flushes out of 1000000 hands: 0.004003
gcc -std=c99 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o cards-aoa ./cards-aoa.c valgrind --leak-check=full ./cards-aoa 2>&1
==16946== Memcheck, a memory error detector ==16946== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==16946== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info ==16946== Command: ./cards-aoa ==16946== Flush found at card 14 Suit 0 Flush found at card 65 Suit 0 Flush found at card 126 Suit 1 Flush found at card 238 Suit 1 Flush found at card 246 Suit 1 Flush found at card 648 Suit 1 Flush found at card 738 Suit 2 Flush found at card 894 Suit 1 Flush found at card 1076 Suit 0 Flush found at card 1175 Suit 2 We found 3845 flushes out of 1000000 hands: 0.003845 ==16946== ==16946== HEAP SUMMARY: ==16946== in use at exit: 0 bytes in 0 blocks ==16946== total heap usage: 1,000,002 allocs, 1,000,002 frees, 48,004,096 bytes allocated ==16946== ==16946== All heap blocks were freed -- no leaks are possible ==16946== ==16946== For counts of detected and suppressed errors, rerun with: -v ==16946== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
1.5.5 Using pointers for protection
#define _POSIX_C_SOURCE 200809L // <-- needed for getline #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> /* Let's define Stack as a pointer to a struct, * which itself contains the pointer to the actual * data on the stack, which are pointers to chars (strings). * * This is so that when we realloc() and update elts, * we don't have to worry about some other piece of code * having the old value of elts. * * If we didn't hide our pointer that gets realloc'd behind * another pointer, it is easy to have an old copy of the * realloc'd pointer (which is now invalid) floating around. * * But by putting it behind a pointer, new_stack() can * create the single copy of the struct, which contains * the elts pointer that changes. Since the sizeof the * actual struct never changes, we never have to realloc * that pointer, so we can ensure we only have one version * of elts at all times. This is similar to how * Java/Python/JS handle arrays internally. * */ // OK so Stack is pointer of struct stack NOT struct stack. typedef struct stack { size_t size; char ** elts; } * Stack; void show_stack(Stack stack) { printf("Stack %p: %zu items starting at %p\n", (void *) stack, stack->size, (void *) stack->elts ); } // This is a good style, new_object, or object_create Stack new_stack() { /* Constructor */ Stack new = malloc(sizeof(*new)); if (new == NULL) { abort(); } new->size = 0; new->elts = NULL; show_stack(new); return new; } /* this function deduplicates code from push and pop */ void resize(Stack stack, size_t new_size) { stack->elts = realloc( stack->elts, sizeof(char *) * new_size ); /* make sure any new elements are initialized */ size_t first_new_elt = stack->size; for (size_t idx = first_new_elt; idx < new_size; idx++) { stack->elts[idx] = NULL; } stack->size = new_size; } void push(Stack stack, char * string) { resize(stack, stack->size + 1); stack->elts[stack->size-1] = string; show_stack(stack); } char * pop(Stack stack) { if (stack->size == 0) { abort(); } char * string = stack->elts[stack->size-1]; resize(stack, stack->size - 1); show_stack(stack); return string; } /* Destructor */ void free_stack(Stack stack) { resize(stack, 0); free(stack); } char * checked_getline() { char * line = NULL; size_t alloc_len = 0; ssize_t got = getline(&line, &alloc_len, stdin); if (got < 0) { if (line != NULL) { free(line); } return NULL; } else { return line; } } void push_input_lines(Stack stack) { printf("Enter some lines. Press ctrl-d (EOF) to end.\n"); char * line = NULL; while ((line = checked_getline()) != NULL) { push(stack, line); } } void pop_lines(Stack stack) { while (stack->size > 0) { char * line = pop(stack); puts(line); free(line); } } int main() { Stack stack1 = new_stack(); Stack stack2 = stack1; /* Because stack is a pointer, stack1 and stack2 are * actually the same stack! * Because the actual struct doesn't need to change size, * these pointers will be valid until we call free_stack() */ push_input_lines(stack1); pop_lines(stack2); free_stack(stack1); return 0; }
Stack 0x56362ee8c260: 0 items starting at (nil) Enter some lines. Press ctrl-d (EOF) to end.
gcc -std=c99 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o stack ./stack.c seq 9990 9999 | ./stack
Stack 0x55f488145260: 0 items starting at (nil) Enter some lines. Press ctrl-d (EOF) to end. Stack 0x55f488145260: 1 items starting at 0x55f488147320 Stack 0x55f488145260: 2 items starting at 0x55f488147320 Stack 0x55f488145260: 3 items starting at 0x55f488147320 Stack 0x55f488145260: 4 items starting at 0x55f4881474c0 Stack 0x55f488145260: 5 items starting at 0x55f4881474c0 Stack 0x55f488145260: 6 items starting at 0x55f4881475f0 Stack 0x55f488145260: 7 items starting at 0x55f4881475f0 Stack 0x55f488145260: 8 items starting at 0x55f488147730 Stack 0x55f488145260: 9 items starting at 0x55f488147730 Stack 0x55f488145260: 10 items starting at 0x55f488147880 Stack 0x55f488145260: 9 items starting at 0x55f488147880 9999 Stack 0x55f488145260: 8 items starting at 0x55f488147880 9998 Stack 0x55f488145260: 7 items starting at 0x55f488147880 9997 Stack 0x55f488145260: 6 items starting at 0x55f488147880 9996 Stack 0x55f488145260: 5 items starting at 0x55f488147880 9995 Stack 0x55f488145260: 4 items starting at 0x55f488147880 9994 Stack 0x55f488145260: 3 items starting at 0x55f488147880 9993 Stack 0x55f488145260: 2 items starting at 0x55f488147880 9992 Stack 0x55f488145260: 1 items starting at 0x55f488147880 9991 Stack 0x55f488145260: 0 items starting at (nil) 9990
1.6 Objects and APIs
When you make a new type you should follow some guidelines:
- put the name of the type at the start or end of function names:
- For type dog:
- dogcreate()
- dogfree(dog)
- dogmove(dog,x,y)
- dogbark(dog, barkspec)
- createDog()
- freeDog(dog)
- moveDog(dog,x,y)
- barkDog(dog, barkSpec)
- For type cat:
- createCat()
- freeCat(cat)
- moveCat(cat)
- meowCat(cat, meowspec)
- catcreate()
- catfree(cat)
- catmove(cat)
- catmeow(cat, meowspec)
- For type dog:
- Should your type be a struct or a pointer to a struct?
- struct pros:
- functional
- easy to copy
- stay on the stack
- safe shallow copy of data
- don't have to free
- struct cons:
- if structs have pointers then copies of structs might have old pointers
- doesn't play well we malloc and realloc
- stale info
- hard to ensure consistency
- big
- pointer to struct pros:
- small to pass (1 pointer)
- can have multiple references
- more control
- can hide implementation better
- consistency
- malloc and realloc friendly.
- pointer to struct cons:
- malloc
- must free
- hard to copy
- deepcopy required
- awkward with arrays
- struct pros:
1.6.1 original stack example
#define _POSIX_C_SOURCE 200809L // <-- needed for getline #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> /* Let's define Stack as a pointer to a struct, * which itself contains the pointer to the actual * data on the stack, which are pointers to chars (strings). * * This is so that when we realloc() and update elts, * we don't have to worry about some other piece of code * having the old value of elts. * * If we didn't hide our pointer that gets realloc'd behind * another pointer, it is easy to have an old copy of the * realloc'd pointer (which is now invalid) floating around. * * But by putting it behind a pointer, new_stack() can * create the single copy of the struct, which contains * the elts pointer that changes. Since the sizeof the * actual struct never changes, we never have to realloc * that pointer, so we can ensure we only have one version * of elts at all times. This is similar to how * Java/Python/JS handle arrays internally. * */ // OK so Stack is pointer of struct stack NOT struct stack. typedef struct stack { size_t size; char ** elts; } * Stack; void show_stack(Stack stack) { printf("Stack %p: %zu items starting at %p\n", (void *) stack, stack->size, (void *) stack->elts ); } // This is a good style, new_object, or object_create Stack new_stack() { /* Constructor */ Stack new = malloc(sizeof(*new)); new->size = 0; new->elts = NULL; show_stack(new); return new; } /* this function deduplicates code from push and pop */ void resize(Stack stack, size_t new_size) { stack->elts = realloc( stack->elts, sizeof(char *) * new_size ); /* make sure any new elements are initialized */ size_t first_new_elt = stack->size; for (size_t idx = first_new_elt; idx < new_size; idx++) { stack->elts[idx] = NULL; } stack->size = new_size; } void push(Stack stack, char * string) { resize(stack, stack->size + 1); stack->elts[stack->size-1] = string; show_stack(stack); } char * pop(Stack stack) { if (stack->size == 0) { abort(); } char * string = stack->elts[stack->size-1]; resize(stack, stack->size - 1); show_stack(stack); return string; } /* Destructor */ void free_stack(Stack stack) { resize(stack, 0); free(stack); } char * checked_getline() { char * line = NULL; size_t alloc_len = 0; ssize_t got = getline(&line, &alloc_len, stdin); if (got < 0) { if (line != NULL) { free(line); } return NULL; } else { return line; } } void push_input_lines(Stack stack) { printf("Enter some lines. Press ctrl-d (EOF) to end.\n"); char * line = NULL; while ((line = checked_getline()) != NULL) { push(stack, line); } } void pop_lines(Stack stack) { while (stack->size > 0) { char * line = pop(stack); puts(line); free(line); } } int main() { Stack stack1 = new_stack(); Stack stack2 = stack1; /* Because stack is a pointer, stack1 and stack2 are * actually the same stack! * Because the actual struct doesn't need to change size, * these pointers will be valid until we call free_stack() */ push_input_lines(stack1); pop_lines(stack2); free_stack(stack1); return 0; }
Stack 0x55f01a3ba260: 0 items starting at (nil) Enter some lines. Press ctrl-d (EOF) to end.
1.6.2 Recommended stack example
#define _POSIX_C_SOURCE 200809L // <-- needed for getline #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> /* Let's define Stack as a pointer to a struct, * which itself contains the pointer to the actual * data on the stack, which are pointers to chars (strings). * * This is so that when we realloc() and update elts, * we don't have to worry about some other piece of code * having the old value of elts. * * If we didn't hide our pointer that gets realloc'd behind * another pointer, it is easy to have an old copy of the * realloc'd pointer (which is now invalid) floating around. * * But by putting it behind a pointer, new_stack() can * create the single copy of the struct, which contains * the elts pointer that changes. Since the sizeof the * actual struct never changes, we never have to realloc * that pointer, so we can ensure we only have one version * of elts at all times. This is similar to how * Java/Python/JS handle arrays internally. * */ // OK so Stack is pointer of struct stack NOT struct stack. typedef struct stack { size_t size; char ** elts; } * Stack; void show_stack(Stack stack) { printf("Stack %p: %zu items starting at %p\n", (void *) stack, stack->size, (void *) stack->elts ); } // This is a good style, new_object, or object_create Stack new_stack() { /* Constructor */ Stack new = malloc(sizeof(*new)); new->size = 0; new->elts = NULL; show_stack(new); return new; } /* this function deduplicates code from push and pop */ void resize_stack(Stack stack, size_t new_size) { stack->elts = realloc( stack->elts, sizeof(char *) * new_size ); /* make sure any new elements are initialized */ size_t first_new_elt = stack->size; for (size_t idx = first_new_elt; idx < new_size; idx++) { stack->elts[idx] = NULL; } stack->size = new_size; } void push_stack(Stack stack, char * string) { resize_stack(stack, stack->size + 1); stack->elts[stack->size-1] = string; show_stack(stack); } char * pop_stack(Stack stack) { if (stack->size == 0) { abort(); } char * string = stack->elts[stack->size-1]; resize_stack(stack, stack->size - 1); show_stack(stack); return string; } /* Destructor */ void free_stack(Stack stack) { resize_stack(stack, 0); free(stack); } char * checked_getline() { char * line = NULL; size_t alloc_len = 0; ssize_t got = getline(&line, &alloc_len, stdin); if (got < 0) { if (line != NULL) { free(line); } return NULL; } else { return line; } } void push_input_lines_stack(Stack stack) { printf("Enter some lines. Press ctrl-d (EOF) to end.\n"); char * line = NULL; while ((line = checked_getline()) != NULL) { push_stack(stack, line); } } void pop_lines_stack(Stack stack) { while (stack->size > 0) { char * line = pop_stack(stack); puts(line); free(line); } } int main() { Stack stack1 = new_stack(); Stack stack2 = stack1; /* Because stack is a pointer, stack1 and stack2 are * actually the same stack! * Because the actual struct doesn't need to change size, * these pointers will be valid until we call free_stack() */ push_input_lines_stack(stack1); pop_lines_stack(stack2); free_stack(stack1); return 0; }
Stack 0x55b4c76de260: 0 items starting at (nil) Enter some lines. Press ctrl-d (EOF) to end.
gcc -std=c99 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o new_stack ./new_stack.c seq 9990 9999 | ./new_stack
Stack 0x56180d47c260: 0 items starting at (nil) Enter some lines. Press ctrl-d (EOF) to end. Stack 0x56180d47c260: 1 items starting at 0x56180d47e320 Stack 0x56180d47c260: 2 items starting at 0x56180d47e320 Stack 0x56180d47c260: 3 items starting at 0x56180d47e320 Stack 0x56180d47c260: 4 items starting at 0x56180d47e4c0 Stack 0x56180d47c260: 5 items starting at 0x56180d47e4c0 Stack 0x56180d47c260: 6 items starting at 0x56180d47e5f0 Stack 0x56180d47c260: 7 items starting at 0x56180d47e5f0 Stack 0x56180d47c260: 8 items starting at 0x56180d47e730 Stack 0x56180d47c260: 9 items starting at 0x56180d47e730 Stack 0x56180d47c260: 10 items starting at 0x56180d47e880 Stack 0x56180d47c260: 9 items starting at 0x56180d47e880 9999 Stack 0x56180d47c260: 8 items starting at 0x56180d47e880 9998 Stack 0x56180d47c260: 7 items starting at 0x56180d47e880 9997 Stack 0x56180d47c260: 6 items starting at 0x56180d47e880 9996 Stack 0x56180d47c260: 5 items starting at 0x56180d47e880 9995 Stack 0x56180d47c260: 4 items starting at 0x56180d47e880 9994 Stack 0x56180d47c260: 3 items starting at 0x56180d47e880 9993 Stack 0x56180d47c260: 2 items starting at 0x56180d47e880 9992 Stack 0x56180d47c260: 1 items starting at 0x56180d47e880 9991 Stack 0x56180d47c260: 0 items starting at (nil) 9990
1.6.3 Test First Top Down Design
1.7 Recursive Definitions
1.7.1 Mutually Recursive functions
How do you get functions to call each other when they need each other to be defined?
Function prototypes!
#include <stdio.h> #include <stdint.h> #include <stdlib.h> int64_t addThenDecrementThenMul( int64_t current ); int64_t mulThenDecrementThenAdd( int64_t current ); int64_t addThenDecrementThenMul( int64_t current ) { if (current <= 0) { return current; } return current + mulThenDecrementThenAdd( current - 1 ); } int64_t mulThenDecrementThenAdd( int64_t current ) { if (current <= 0) { return current; } return current * addThenDecrementThenMul( current - 1 ); } int main() { for (int i = 0 ; i < 33 ; i++ ) { printf("addThenDecrementThenMul(%4d) ==%19ld\n", i, addThenDecrementThenMul( i )); //printf("mulThenDecrementThenAdd(%4d) ==%19ld\n", i, mulThenDecrementThenAdd( i )); } }
addThenDecrementThenMul( 0) == 0 addThenDecrementThenMul( 1) == 1 addThenDecrementThenMul( 2) == 2 addThenDecrementThenMul( 3) == 5 addThenDecrementThenMul( 4) == 10 addThenDecrementThenMul( 5) == 25 addThenDecrementThenMul( 6) == 56 addThenDecrementThenMul( 7) == 157 addThenDecrementThenMul( 8) == 400 addThenDecrementThenMul( 9) == 1265 addThenDecrementThenMul( 10) == 3610 addThenDecrementThenMul( 11) == 12661 addThenDecrementThenMul( 12) == 39722 addThenDecrementThenMul( 13) == 151945 addThenDecrementThenMul( 14) == 516400 addThenDecrementThenMul( 15) == 2127245 addThenDecrementThenMul( 16) == 7746016 addThenDecrementThenMul( 17) == 34035937 addThenDecrementThenMul( 18) == 131682290 addThenDecrementThenMul( 19) == 612646885 addThenDecrementThenMul( 20) ==<PHONE_NUMBER> addThenDecrementThenMul( 21) ==<PHONE_NUMBER>1 addThenDecrementThenMul( 22) ==<PHONE_NUMBER>2 addThenDecrementThenMul( 23) ==<PHONE_NUMBER>85 addThenDecrementThenMul( 24) ==<PHONE_NUMBER>520 addThenDecrementThenMul( 25) ==<PHONE_NUMBER>265 addThenDecrementThenMul( 26) ==<PHONE_NUMBER>8026 addThenDecrementThenMul( 27) ==<PHONE_NUMBER>48917 addThenDecrementThenMul( 28) ==<PHONE_NUMBER>26730 addThenDecrementThenMul( 29) ==<PHONE_NUMBER>369705 addThenDecrementThenMul( 30) ==<PHONE_NUMBER>6575200 addThenDecrementThenMul( 31) ==<PHONE_NUMBER>01091181 addThenDecrementThenMul( 32) ==<PHONE_NUMBER>43831232
If you don't use prototypes on your mutual recursive functions you will get errors like
/tmp/babel-25087Va_/C-src-25087Eoy.c: In function ‘addThenDecrementThenMul’: /tmp/babel-25087Va_/C-src-25087Eoy.c:21:22: warning: implicit declaration of function ‘mulThenDecrementThenAdd’; did you mean ‘addThenDecrementThenMul’? [-Wimplicit-function-declaration] return current + mulThenDecrementThenAdd( current - 1 ); ^~~~~~~~~~~~~~~~~~~~~~~ addThenDecrementThenMul /tmp/babel-25087Va_/C-src-25087Eoy.c: At top level: /tmp/babel-25087Va_/C-src-25087Eoy.c:24:9: error: conflicting types for ‘mulThenDecrementThenAdd’ int64_t mulThenDecrementThenAdd( int64_t current ) { ^~~~~~~~~~~~~~~~~~~~~~~ /tmp/babel-25087Va_/C-src-25087Eoy.c:21:22: note: previous implicit declaration of ‘mulThenDecrementThenAdd’ was here return current + mulThenDecrementThenAdd( current - 1 ); ^~~~~~~~~~~~~~~~~~~~~~~ /bin/bash: /tmp/babel-25087Va_/C-bin-250872xB: Permission denied
1.7.2 Recursive Structs
#include <stdio.h> #include <stdint.h> #include <stdlib.h> enum atype { INT, LONG, DOUBLE, FLOAT, }; union anything { int anInt; long aLong; double aDouble; float aFloat; }; struct linkedList; struct linkedList { enum atype type; union anything value; struct linkedList *next; }; struct linkedList * allocLinkedList( enum atype type, union anything value, struct linkedList * next) { struct linkedList * node = malloc(sizeof(*node)); node->type = type; node->value = value; node->next = next; return node; } void freeLinkedList( struct linkedList * list) { if (list == NULL ){ return; } freeLinkedList( list->next ); free( list ); } void freeLinkedListIterative( struct linkedList * list) { while( list != NULL ) { struct linkedList * freeMe = list; list = list->next; free(freeMe); } } int main() { union anything v = {.aDouble = 1.2 }; struct linkedList * tail = allocLinkedList( DOUBLE, v, NULL); struct linkedList * head = tail; for (int i = 0 ; i < 10; i++) { v.anInt = i*2; head = allocLinkedList( INT, v, head ); } struct linkedList * iter = head; while(iter!=NULL) { if (iter->type == INT) { printf("Print node value: %5d next: %p\n", iter->value.anInt, (void*)iter->next); } else { printf("Print node type: %5d next: %p\n", iter->type, (void*)iter->next); } iter = iter->next; // iter->next ===> iter } // freeLinkedList( head ); // freeLinkedListIterative( head ); return 0; }
Print node value: 18 next: 0x55e6b82b8380 Print node value: 16 next: 0x55e6b82b8360 Print node value: 14 next: 0x55e6b82b8340 Print node value: 12 next: 0x55e6b82b8320 Print node value: 10 next: 0x55e6b82b8300 Print node value: 8 next: 0x55e6b82b82e0 Print node value: 6 next: 0x55e6b82b82c0 Print node value: 4 next: 0x55e6b82b82a0 Print node value: 2 next: 0x55e6b82b8280 Print node value: 0 next: 0x55e6b82b8260 Print node type: 2 next: (nil)
gcc -std=c99 -Wall -pedantic -Werror -o linkedlist ./linkedlist.c valgrind ./linkedlist 2>&1 echo now let\'s leak check valgrind --leak-check=full ./linkedlist 2>&1
==19776== Memcheck, a memory error detector ==19776== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==19776== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info ==19776== Command: ./linkedlist ==19776== Print node value: 18 next: 0x522d3a0 Print node value: 16 next: 0x522d340 Print node value: 14 next: 0x522d2e0 Print node value: 12 next: 0x522d280 Print node value: 10 next: 0x522d220 Print node value: 8 next: 0x522d1c0 Print node value: 6 next: 0x522d160 Print node value: 4 next: 0x522d100 Print node value: 2 next: 0x522d0a0 Print node value: 0 next: 0x522d040 Print node type: 2 next: (nil) ==19776== ==19776== HEAP SUMMARY: ==19776== in use at exit: 264 bytes in 11 blocks ==19776== total heap usage: 12 allocs, 1 frees, 4,360 bytes allocated ==19776== ==19776== LEAK SUMMARY: ==19776== definitely lost: 24 bytes in 1 blocks ==19776== indirectly lost: 240 bytes in 10 blocks ==19776== possibly lost: 0 bytes in 0 blocks ==19776== still reachable: 0 bytes in 0 blocks ==19776== suppressed: 0 bytes in 0 blocks ==19776== Rerun with --leak-check=full to see details of leaked memory ==19776== ==19776== For counts of detected and suppressed errors, rerun with: -v ==19776== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) now let's leak check ==19782== Memcheck, a memory error detector ==19782== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==19782== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info ==19782== Command: ./linkedlist ==19782== Print node value: 18 next: 0x522d3a0 Print node value: 16 next: 0x522d340 Print node value: 14 next: 0x522d2e0 Print node value: 12 next: 0x522d280 Print node value: 10 next: 0x522d220 Print node value: 8 next: 0x522d1c0 Print node value: 6 next: 0x522d160 Print node value: 4 next: 0x522d100 Print node value: 2 next: 0x522d0a0 Print node value: 0 next: 0x522d040 Print node type: 2 next: (nil) ==19782== ==19782== HEAP SUMMARY: ==19782== in use at exit: 264 bytes in 11 blocks ==19782== total heap usage: 12 allocs, 1 frees, 4,360 bytes allocated ==19782== ==19782== 264 (24 direct, 240 indirect) bytes in 1 blocks are definitely lost in loss record 3 of 3 ==19782== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==19782== by 0x1086F6: allocLinkedList (in /home/hindle1/projects/CMPUT201/CMPUT201W20B2-public/week08/linkedlist) ==19782== by 0x1087EA: main (in /home/hindle1/projects/CMPUT201/CMPUT201W20B2-public/week08/linkedlist) ==19782== ==19782== LEAK SUMMARY: ==19782== definitely lost: 24 bytes in 1 blocks ==19782== indirectly lost: 240 bytes in 10 blocks ==19782== possibly lost: 0 bytes in 0 blocks ==19782== still reachable: 0 bytes in 0 blocks ==19782== suppressed: 0 bytes in 0 blocks ==19782== ==19782== For counts of detected and suppressed errors, rerun with: -v ==19782== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
This is what happens when we don't free
==6238== Memcheck, a memory error detector ==6238== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==6238== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info ==6238== Command: ./linkedlist ==6238== Print node value: 18 next: 0x522d3a0 Print node value: 16 next: 0x522d340 Print node value: 14 next: 0x522d2e0 Print node value: 12 next: 0x522d280 Print node value: 10 next: 0x522d220 Print node value: 8 next: 0x522d1c0 Print node value: 6 next: 0x522d160 Print node value: 4 next: 0x522d100 Print node value: 2 next: 0x522d0a0 Print node value: 0 next: 0x522d040 Print node value: 32 next: (nil) ==6238== ==6238== HEAP SUMMARY: ==6238== in use at exit: 264 bytes in 11 blocks ==6238== total heap usage: 12 allocs, 1 frees, 4,360 bytes allocated ==6238== ==6238== LEAK SUMMARY: ==6238== definitely lost: 24 bytes in 1 blocks ==6238== indirectly lost: 240 bytes in 10 blocks ==6238== possibly lost: 0 bytes in 0 blocks ==6238== still reachable: 0 bytes in 0 blocks ==6238== suppressed: 0 bytes in 0 blocks ==6238== Rerun with --leak-check=full to see details of leaked memory ==6238== ==6238== For counts of detected and suppressed errors, rerun with: -v ==6238== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) now let's leak check ==6239== Memcheck, a memory error detector ==6239== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==6239== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info ==6239== Command: ./linkedlist ==6239== Print node value: 18 next: 0x522d3a0 Print node value: 16 next: 0x522d340 Print node value: 14 next: 0x522d2e0 Print node value: 12 next: 0x522d280 Print node value: 10 next: 0x522d220 Print node value: 8 next: 0x522d1c0 Print node value: 6 next: 0x522d160 Print node value: 4 next: 0x522d100 Print node value: 2 next: 0x522d0a0 Print node value: 0 next: 0x522d040 Print node value: 32 next: (nil) ==6239== ==6239== HEAP SUMMARY: ==6239== in use at exit: 264 bytes in 11 blocks ==6239== total heap usage: 12 allocs, 1 frees, 4,360 bytes allocated ==6239== ==6239== 264 (24 direct, 240 indirect) bytes in 1 blocks are definitely lost in loss record 3 of 3 ==6239== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==6239== by 0x1086F6: allocLinkedList (in /home/hindle1/projects/CMPUT201W20/2020-01/CMPUT201W20B2-public/week08/linkedlist) ==6239== by 0x1087B4: main (in /home/hindle1/projects/CMPUT201W20/2020-01/CMPUT201W20B2-public/week08/linkedlist) ==6239== ==6239== LEAK SUMMARY: ==6239== definitely lost: 24 bytes in 1 blocks ==6239== indirectly lost: 240 bytes in 10 blocks ==6239== possibly lost: 0 bytes in 0 blocks ==6239== still reachable: 0 bytes in 0 blocks ==6239== suppressed: 0 bytes in 0 blocks ==6239== ==6239== For counts of detected and suppressed errors, rerun with: -v ==6239== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
1.7.3 Mutually Recursive Structs
#include <stdio.h> #include <stdint.h> #include <stdlib.h> struct x; struct y; // field X and Y have incomplete types, NOT ALLOWED // try uncommenting this // struct z { struct x X; struct y Y; }; struct x { struct y *yPtr; }; struct y { struct x *xPtr; }; struct z { struct x X; struct y Y; }; int main() { struct x sX = { .yPtr = NULL }; struct y sY = { .xPtr = &sX }; sX.yPtr = &sY; struct z sZ = { .X = sX, .Y = sY }; printf("sX: %6zu\n", sizeof(sX)); printf("sY: %6zu\n", sizeof(sY)); printf("sZ: %6zu\n", sizeof(sZ)); printf("sZ.X.yPtr:\t %p\n", (void*)sZ.X.yPtr); printf("sZ.Y.xPtr:\t %p\n", (void*)sZ.Y.xPtr); printf("&sX:\t\t %p\n", (void*)&sX); printf("&sY:\t\t %p\n", (void*)&sY); printf("&sZ.X:\t %p\n", (void*)&(sZ.X)); printf("&sY.Y:\t %p\n", (void*)&(sZ.Y)); return 0; }
sX: 8 sY: 8 sZ: 16 sZ.X.yPtr: 0x7fff45c69d28 sZ.Y.xPtr: 0x7fff45c69d20 &sX: 0x7fff45c69d20 &sY: 0x7fff45c69d28 &sZ.X: 0x7fff45c69d30 &sY.Y: 0x7fff45c69d38
1.8 Debugging
1.8.1 GDB
- debuggers let us step through programs and observe variables.
- Compile a program with -g or -ggdb3 with gcc or clang
- this adds debugging symbols (so you can read it!)
- tell gdb to use your program
- gdb ./a.out
- tell gdb to run your program
- run
- tell gbd to print a backtrace when something crashes
- bt
- tell gdb to print a variable name
- p string
- tell gdb to break at some point
- b filename:function
- b filename:line
- b line
- b function
- tell gdb to step into code (including into functions)
- s
- tell gdb to eval the next line (run functions)
- n
- keep running (continue)
- c
- print source code (list)
- l
- remove breakpoint
- clear
- clear function
- clear line
- quit
- q
- man gdb to get more help
- GDB manual http://sourceware.org/gdb/current/onlinedocs/gdb/
- ctrl-x a put gdb in curses semi-graphical mode
- ddd is a graphical wrapper for gdb (probably not in your VM)
- I like ctrl-x a better
hindle1@frail:~/projects/CMPUT201/CMPUT201W20B2-public/week08$ gdb ./bad_realloc GNU gdb (Ubuntu 8.1-0ubuntu3.2) <IP_ADDRESS>80409-git Copyright (C) 2018 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from ./bad_realloc...done. (gdb) run Starting program: /home/hindle1/projects/CMPUT201/CMPUT201W20B2-public/week08/bad_realloc Stack: 0 items starting at (nil) Enter some lines. Press ctrl-d (EOF) to end. 100 Program received signal SIGSEGV, Segmentation fault. 0x00005555555549a1 in push (stack=..., string=0x555555757670 "100\n") at ./bad_realloc.c:54 54 stack.elts[stack.size-1] = string; (gdb) p The history is empty. (gdb) bt #0 0x00005555555549a1 in push (stack=..., string=0x555555757670 "100\n") at ./bad_realloc.c:54 #1 0x0000555555554b30 in push_input_lines (stack=...) at ./bad_realloc.c:91 #2 0x0000555555554be0 in main () at ./bad_realloc.c:111 (gdb) p stack $1 = {size = 0, elts = 0x0} (gdb) p stack.size $2 = 0 (gdb) p stack.elts $3 = (char **) 0x0 (gdb) p string $4 = 0x555555757670 "100\n" (gdb) l 49 stack.size = new_size; 50 } 51 52 void push(Stack stack, char * string) { 53 resize(stack, stack.size + 1); 54 stack.elts[stack.size-1] = string; 55 show_stack(stack); 56 } 57 58 char * pop(Stack stack) { (gdb)
Here's a longer example of GDB
hindle1@frail:~/projects/CMPUT201/CMPUT201W20B2-public/week08$ gdb ./cards-aoa GNU gdb (Ubuntu 8.1-0ubuntu3.2) <IP_ADDRESS>80409-git Copyright (C) 2018 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from ./cards-aoa...done. (gdb) b isFlush Breakpoint 1 at 0x806: file ./cards-aoa.c, line 50. (gdb) run Starting program: /home/hindle1/projects/CMPUT201/CMPUT201W20B2-public/week08/cards-aoa Breakpoint 1, isFlush (hand=0x555555757260) at ./cards-aoa.c:50 warning: Source file is more recent than executable. 50 CardSuit suit = hand[0].suit; (gdb) c Continuing. Breakpoint 1, isFlush (hand=0x555555757290) at ./cards-aoa.c:50 50 CardSuit suit = hand[0].suit; (gdb) c Continuing. Breakpoint 1, isFlush (hand=0x5555557572c0) at ./cards-aoa.c:50 50 CardSuit suit = hand[0].suit; (gdb) c Continuing. Breakpoint 1, isFlush (hand=0x5555557572f0) at ./cards-aoa.c:50 50 CardSuit suit = hand[0].suit; (gdb) p hand $1 = (PlayingCard *) 0x5555557572f0 (gdb) p hand[0] $2 = {face = QUEEN, suit = DIAMONDS} (gdb) p hand[0].suit $3 = DIAMONDS (gdb) s 51 for (int i = 1; i < HANDSIZE; i++ ) { (gdb) s 52 if (suit != hand[i].suit) { (gdb) s 53 return false; (gdb) s 57 } (gdb) s main () at ./cards-aoa.c:88 88 for (int i = 0; i < HANDS; i++) { (gdb) s 89 if (isFlush(hands[i])) { (gdb) s Breakpoint 1, isFlush (hand=0x555555757320) at ./cards-aoa.c:50 50 CardSuit suit = hand[0].suit; (gdb) s 51 for (int i = 1; i < HANDSIZE; i++ ) { (gdb) s 52 if (suit != hand[i].suit) { (gdb) s 53 return false; (gdb) s 57 } (gdb) s main () at ./cards-aoa.c:88 88 for (int i = 0; i < HANDS; i++) { (gdb) s 89 if (isFlush(hands[i])) { (gdb) s Breakpoint 1, isFlush (hand=0x555555757350) at ./cards-aoa.c:50 50 CardSuit suit = hand[0].suit; (gdb) n 51 for (int i = 1; i < HANDSIZE; i++ ) { (gdb) n 52 if (suit != hand[i].suit) { (gdb) n 51 for (int i = 1; i < HANDSIZE; i++ ) { (gdb) n 52 if (suit != hand[i].suit) { (gdb) n 53 return false; (gdb) n 57 } (gdb) n main () at ./cards-aoa.c:88 88 for (int i = 0; i < HANDS; i++) { (gdb) n 89 if (isFlush(hands[i])) { (gdb) n Breakpoint 1, isFlush (hand=0x555555757380) at ./cards-aoa.c:50 50 CardSuit suit = hand[0].suit; (gdb) clear isFlush Deleted breakpoint 1 (gdb) c Continuing. Flush found at card 228 Suit 3 Flush found at card 291 Suit 2 Flush found at card 846 Suit 1 Flush found at card 886 Suit 2 Flush found at card 892 Suit 0 Flush found at card 1102 Suit 2 Flush found at card 1104 Suit 0 Flush found at card 1437 Suit 0 Flush found at card 1872 Suit 1 Flush found at card 2156 Suit 2 We found 3857 flushes out of 1000000 hands: 0.003857 [Inferior 1 (process 18051) exited normally] (gdb) q
1.8.2 valgrind
- Valgrind can debug memory issues like
- unitialized values
- memory leaks
- reading/writing free'd memory
- bad use of the stack (not great)
- valgrind ./yourprogram
- valgrind –tool=memcheck ./yourprogram
- valgrind –tool=exp-sgcheck ./yourprogram
- for stack checks (not great)
- There's always the manual https://valgrind.org/docs/manual/manual.html
- do you want a lot of output?
- valgrind –leak-check=full –show-leak-kinds=all –track-origins=yes –verbose ./yourprgram
- Array Out of Bounds
#define _POSIX_C_SOURCE 200809L #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> /* * This is an example of BAD CODE! * Can you use valgrind and gdb * to figure out what's wrong with it? */ int main() { size_t size; printf("How big?\n"); if (scanf("%zu", &size) != 1) { abort(); } int array[size]; for (size_t idx = 0; idx < size; idx++) { array[idx] = 0; } printf("%d\n", array[100]); array[100] += 1; printf("%d\n", array[100]); return 0; }
gcc -std=c99 -O0 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o array_oob ./array_oob.c echo 32 | ./array_oob echo $?
How big? 0 1 0
gcc -std=c99 -O0 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o array_oob ./array_oob.c echo 6 | valgrind --leak-check=full ./array_oob 2>&1 echo $?
==21934== Memcheck, a memory error detector ==21934== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==21934== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info ==21934== Command: ./array_oob ==21934== How big? -16775049 -16775048 ==21934== ==21934== HEAP SUMMARY: ==21934== in use at exit: 0 bytes in 0 blocks ==21934== total heap usage: 2 allocs, 2 frees, 8,192 bytes allocated ==21934== ==21934== All heap blocks were freed -- no leaks are possible ==21934== ==21934== For counts of detected and suppressed errors, rerun with: -v ==21934== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) 0
The output is dependent on your input
gcc -std=c99 --stack-check -pedantic -Wall -Wextra -ftrapv -g3 -o array_oob ./array_oob.c || echo did not compile echo 32 | valgrind --tool=exp-sgcheck ./array_oob 2>&1 echo $?
==21996== exp-sgcheck, a stack and global array overrun detector ==21996== NOTE: This is an Experimental-Class Valgrind Tool ==21996== Copyright (C) 2003-2017, and GNU GPL'd, by OpenWorks Ltd et al. ==21996== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info ==21996== Command: ./array_oob ==21996== --21996-- warning: evaluate_Dwarf3_Expr: unhandled DW_OP_ 0x93 --21996-- warning: evaluate_Dwarf3_Expr: unhandled DW_OP_ 0x93 --21996-- warning: evaluate_Dwarf3_Expr: unhandled DW_OP_ 0x93 --21996-- warning: evaluate_Dwarf3_Expr: unhandled DW_OP_ 0x93 --21996-- warning: evaluate_Dwarf3_Expr: unhandled DW_OP_ 0x93 --21996-- warning: evaluate_Dwarf3_Expr: unhandled DW_OP_ 0x93 --21996-- warning: evaluate_Dwarf3_Expr: unhandled DW_OP_ 0x93 --21996-- warning: evaluate_Dwarf3_Expr: unhandled DW_OP_ 0x93 --21996-- warning: evaluate_Dwarf3_Expr: unhandled DW_OP_ 0x93 --21996-- warning: evaluate_Dwarf3_Expr: unhandled DW_OP_ 0x93 --21996-- warning: evaluate_Dwarf3_Expr: unhandled DW_OP_ 0x93 --21996-- warning: evaluate_Dwarf3_Expr: unhandled DW_OP_ 0x93 --21996-- warning: evaluate_Dwarf3_Expr: unhandled DW_OP_ 0x93 --21996-- warning: evaluate_Dwarf3_Expr: unhandled DW_OP_ 0x93 --21996-- warning: evaluate_Dwarf3_Expr: unhandled DW_OP_ 0x93 --21996-- warning: evaluate_Dwarf3_Expr: unhandled DW_OP_ 0x93 How big? 0 1 ==21996== ==21996== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2) 0
gcc -std=c99 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o array_oob ./array_oob.c gnome-terminal -- gdb ./array_oob
- Array unitialized
#define _POSIX_C_SOURCE 200809L #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> /* * This is an example of BAD CODE! * Can you use valgrind and gdb * to figure out what's wrong with it? */ int main() { size_t size; printf("How big?\n"); if (scanf("%zu", &size) != 1) { abort(); } int array[size]; for (size_t idx = 0; idx < size; idx++) { printf("%d\n", array[idx]); } return 0; }
gcc -std=c99 -O0 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o array_uninit ./array_uninit.c echo 10 | ./array_uninit echo $?
How big? -782409112 32764 0 0 -782673888 32764 -782673984 32764 0 0 0
gcc -std=c99 -O0 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o array_uninit ./array_uninit.c echo 5 | valgrind --leak-check=full ./array_uninit 2>&1 echo $?
==16458== Memcheck, a memory error detector ==16458== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==16458== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info ==16458== Command: ./array_uninit ==16458== ==16458== Conditional jump or move depends on uninitialised value(s) ==16458== at 0x4E988DA: vfprintf (vfprintf.c:1642) ==16458== by 0x4EA0F25: printf (printf.c:33) ==16458== by 0x108891: main (array_uninit.c:24) ==16458== ==16458== Use of uninitialised value of size 8 ==16458== at 0x4E9486B: _itoa_word (_itoa.c:179) ==16458== by 0x4E97F0D: vfprintf (vfprintf.c:1642) ==16458== by 0x4EA0F25: printf (printf.c:33) ==16458== by 0x108891: main (array_uninit.c:24) ==16458== ==16458== Conditional jump or move depends on uninitialised value(s) ==16458== at 0x4E94875: _itoa_word (_itoa.c:179) ==16458== by 0x4E97F0D: vfprintf (vfprintf.c:1642) ==16458== by 0x4EA0F25: printf (printf.c:33) ==16458== by 0x108891: main (array_uninit.c:24) ==16458== ==16458== Conditional jump or move depends on uninitialised value(s) ==16458== at 0x4E98014: vfprintf (vfprintf.c:1642) ==16458== by 0x4EA0F25: printf (printf.c:33) ==16458== by 0x108891: main (array_uninit.c:24) ==16458== ==16458== Conditional jump or move depends on uninitialised value(s) ==16458== at 0x4E98B4C: vfprintf (vfprintf.c:1642) ==16458== by 0x4EA0F25: printf (printf.c:33) ==16458== by 0x108891: main (array_uninit.c:24) ==16458== How big? -16776224 31 -16776320 31 0 ==16458== ==16458== HEAP SUMMARY: ==16458== in use at exit: 0 bytes in 0 blocks ==16458== total heap usage: 2 allocs, 2 frees, 8,192 bytes allocated ==16458== ==16458== All heap blocks were freed -- no leaks are possible ==16458== ==16458== For counts of detected and suppressed errors, rerun with: -v ==16458== Use --track-origins=yes to see where uninitialised values come from ==16458== ERROR SUMMARY: 57 errors from 5 contexts (suppressed: 0 from 0) 0
Yeah valgrind did not like that. It complained about uninitiliazed values.
1.8.3 More bad code
These files are debugging examples where you should practice valgrind and gcc.
# look a bash for loop! echo Compiling! for file in ./array_oob.c ./array_uninit.c ./bad_realloc.c ./bad_str.c ./double_free.c ./huge_array.c ./infinite_recursion.c ./malloc.c ./malloc_oob.c ./malloc_uninit.c ./segv.c ./simple_uninit.c ./stack.c ./stack_limit.c ./use_after_free.c do gcc -std=c99 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o `basename -s .c $file` $file done
Compiling!
gcc -std=c99 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o array_oob ./array_oob.c
echo 15 | valgrind ./array_oob 2>&1
==23630== Memcheck, a memory error detector ==23630== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==23630== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info ==23630== Command: ./array_oob ==23630== How big? 0 1 ==23630== ==23630== HEAP SUMMARY: ==23630== in use at exit: 0 bytes in 0 blocks ==23630== total heap usage: 2 allocs, 2 frees, 8,192 bytes allocated ==23630== ==23630== All heap blocks were freed -- no leaks are possible ==23630== ==23630== For counts of detected and suppressed errors, rerun with: -v ==23630== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Run GDB
gcc -std=c99 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o array_oob ./array_oob.c gnome-terminal -- gdb ./array_oob
gcc -std=c99 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o array_uninit ./array_uninit.c
echo 7 | valgrind ./array_uninit 2>&1
==22170== Memcheck, a memory error detector ==22170== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==22170== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info ==22170== Command: ./array_uninit ==22170== ==22170== Conditional jump or move depends on uninitialised value(s) ==22170== at 0x4E988DA: vfprintf (vfprintf.c:1642) ==22170== by 0x4EA0F25: printf (printf.c:33) ==22170== by 0x108891: main (array_uninit.c:24) ==22170== ==22170== Use of uninitialised value of size 8 ==22170== at 0x4E9486B: _itoa_word (_itoa.c:179) ==22170== by 0x4E97F0D: vfprintf (vfprintf.c:1642) ==22170== by 0x4EA0F25: printf (printf.c:33) ==22170== by 0x108891: main (array_uninit.c:24) ==22170== ==22170== Conditional jump or move depends on uninitialised value(s) ==22170== at 0x4E94875: _itoa_word (_itoa.c:179) ==22170== by 0x4E97F0D: vfprintf (vfprintf.c:1642) ==22170== by 0x4EA0F25: printf (printf.c:33) ==22170== by 0x108891: main (array_uninit.c:24) ==22170== ==22170== Conditional jump or move depends on uninitialised value(s) ==22170== at 0x4E98014: vfprintf (vfprintf.c:1642) ==22170== by 0x4EA0F25: printf (printf.c:33) ==22170== by 0x108891: main (array_uninit.c:24) ==22170== ==22170== Conditional jump or move depends on uninitialised value(s) ==22170== at 0x4E98B4C: vfprintf (vfprintf.c:1642) ==22170== by 0x4EA0F25: printf (printf.c:33) ==22170== by 0x108891: main (array_uninit.c:24) ==22170== How big? -16776224 31 -16776320 31 0 0 1083410 ==22170== ==22170== HEAP SUMMARY: ==22170== in use at exit: 0 bytes in 0 blocks ==22170== total heap usage: 2 allocs, 2 frees, 8,192 bytes allocated ==22170== ==22170== All heap blocks were freed -- no leaks are possible ==22170== ==22170== For counts of detected and suppressed errors, rerun with: -v ==22170== Use --track-origins=yes to see where uninitialised values come from ==22170== ERROR SUMMARY: 79 errors from 5 contexts (suppressed: 0 from 0)
Run GDB
gcc -std=c99 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o array_uninit ./array_uninit.c gnome-terminal -- gdb ./array_uninit
gcc -std=c99 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o bad_realloc ./bad_realloc.c
echo 33 | valgrind ./bad_realloc 2>&1
Run GDB
gcc -std=c99 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o bad_realloc ./bad_realloc.c gnome-terminal -- gdb ./bad_realloc
gcc -std=c99 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o bad_str ./bad_str.c
echo Coolbears | valgrind ./bad_str 2>&1
==23374== Memcheck, a memory error detector ==23374== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==23374== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info ==23374== Command: ./bad_str ==23374== ==23374== Invalid write of size 1 ==23374== at 0x4EA8FDD: _IO_vfscanf (vfscanf.c:1103) ==23374== by 0x4EB7FD7: __isoc99_scanf (isoc99_scanf.c:37) ==23374== by 0x108773: main (bad_str.c:17) ==23374== Address 0x522d045 is 0 bytes after a block of size 5 alloc'd ==23374== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==23374== by 0x10874B: main (bad_str.c:15) ==23374== ==23374== Invalid write of size 1 ==23374== at 0x4EAA942: _IO_vfscanf (vfscanf.c:1188) ==23374== by 0x4EB7FD7: __isoc99_scanf (isoc99_scanf.c:37) ==23374== by 0x108773: main (bad_str.c:17) ==23374== Address 0x522d049 is 4 bytes after a block of size 5 alloc'd ==23374== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==23374== by 0x10874B: main (bad_str.c:15) ==23374== ==23374== Invalid read of size 1 ==23374== at 0x4C32D04: strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==23374== by 0x4E994D2: vfprintf (vfprintf.c:1643) ==23374== by 0x4EA0F25: printf (printf.c:33) ==23374== by 0x10878B: main (bad_str.c:18) ==23374== Address 0x522d045 is 0 bytes after a block of size 5 alloc'd ==23374== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==23374== by 0x10874B: main (bad_str.c:15) ==23374== ==23374== Invalid read of size 1 ==23374== at 0x4C371F8: mempcpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==23374== by 0x4EC7993: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1258) ==23374== by 0x4E98FEA: vfprintf (vfprintf.c:1643) ==23374== by 0x4EA0F25: printf (printf.c:33) ==23374== by 0x10878B: main (bad_str.c:18) ==23374== Address 0x522d048 is 3 bytes after a block of size 5 alloc'd ==23374== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==23374== by 0x10874B: main (bad_str.c:15) ==23374== ==23374== Invalid read of size 1 ==23374== at 0x4C3720A: mempcpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==23374== by 0x4EC7993: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1258) ==23374== by 0x4E98FEA: vfprintf (vfprintf.c:1643) ==23374== by 0x4EA0F25: printf (printf.c:33) ==23374== by 0x10878B: main (bad_str.c:18) ==23374== Address 0x522d046 is 1 bytes after a block of size 5 alloc'd ==23374== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==23374== by 0x10874B: main (bad_str.c:15) ==23374== Enter a message: You entered: Coolbears ==23374== ==23374== HEAP SUMMARY: ==23374== in use at exit: 5 bytes in 1 blocks ==23374== total heap usage: 3 allocs, 2 frees, 8,197 bytes allocated ==23374== ==23374== LEAK SUMMARY: ==23374== definitely lost: 5 bytes in 1 blocks ==23374== indirectly lost: 0 bytes in 0 blocks ==23374== possibly lost: 0 bytes in 0 blocks ==23374== still reachable: 0 bytes in 0 blocks ==23374== suppressed: 0 bytes in 0 blocks ==23374== Rerun with --leak-check=full to see details of leaked memory ==23374== ==23374== For counts of detected and suppressed errors, rerun with: -v ==23374== ERROR SUMMARY: 14 errors from 5 contexts (suppressed: 0 from 0)
Run GDB
gcc -std=c99 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o bad_str ./bad_str.c gnome-terminal -- gdb ./bad_str
gcc -std=c99 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o double_free ./double_free.c
echo 33 | valgrind ./double_free 2>&1
==23937== Memcheck, a memory error detector ==23937== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==23937== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info ==23937== Command: ./double_free ==23937== ==23937== Invalid free() / delete / delete[] / realloc() ==23937== at 0x4C30D3B: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==23937== by 0x108904: main (double_free.c:27) ==23937== Address 0x522f0c0 is 0 bytes inside a block of size 132 free'd ==23937== at 0x4C30D3B: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==23937== by 0x1088F8: main (double_free.c:26) ==23937== Block was alloc'd at ==23937== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==23937== by 0x10888E: main (double_free.c:21) ==23937== How big? 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 ==23937== ==23937== HEAP SUMMARY: ==23937== in use at exit: 0 bytes in 0 blocks ==23937== total heap usage: 3 allocs, 4 frees, 8,324 bytes allocated ==23937== ==23937== All heap blocks were freed -- no leaks are possible ==23937== ==23937== For counts of detected and suppressed errors, rerun with: -v ==23937== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Run GDB
gcc -std=c99 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o double_free ./double_free.c gnome-terminal -- gdb ./double_free
gcc -std=c99 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o huge_array ./huge_array.c
echo 33 | valgrind ./huge_array 2>&1
==27323== Memcheck, a memory error detector ==27323== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==27323== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info ==27323== Command: ./huge_array ==27323== ==27323== Warning: client switching stacks? SP change: 0x1fff0003e0 --> 0x1ffe8003d0 ==27323== to suppress, use: --max-stackframe=8388624 or greater ==27323== Invalid write of size 8 ==27323== at 0x108728: main (huge_array.c:14) ==27323== Address 0x1ffe8003c8 is on thread 1's stack ==27323== in frame #0, created by main (huge_array.c:13) ==27323== ==27323== Invalid write of size 8 ==27323== at 0x4C36657: memset (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==27323== by 0x10872C: main (huge_array.c:14) ==27323== Address 0x1ffe8003d0 is on thread 1's stack ==27323== in frame #1, created by main (huge_array.c:13) ==27323== ==27323== Invalid write of size 8 ==27323== at 0x4C3665A: memset (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==27323== by 0x10872C: main (huge_array.c:14) ==27323== Address 0x1ffe8003d8 is on thread 1's stack ==27323== in frame #1, created by main (huge_array.c:13) ==27323== ==27323== Invalid write of size 8 ==27323== at 0x4C3665E: memset (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==27323== by 0x10872C: main (huge_array.c:14) ==27323== Address 0x1ffe8003e0 is on thread 1's stack ==27323== in frame #1, created by main (huge_array.c:13) ==27323== ==27323== Invalid write of size 8 ==27323== at 0x4C36662: memset (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==27323== by 0x10872C: main (huge_array.c:14) ==27323== Address 0x1ffe8003e8 is on thread 1's stack ==27323== in frame #1, created by main (huge_array.c:13) ==27323== ==27323== Invalid read of size 8 ==27323== at 0x4C366D5: memset (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==27323== by 0x10872C: main (huge_array.c:14) ==27323== Address 0x1ffe8003c8 is on thread 1's stack ==27323== in frame #0, created by memset (???:) ==27323== ==27323== Invalid read of size 4 ==27323== at 0x10872D: main (huge_array.c:15) ==27323== Address 0x1ffe8003d0 is on thread 1's stack ==27323== in frame #0, created by main (huge_array.c:13) ==27323== ==27323== Warning: client switching stacks? SP change: 0x1ffe8003d0 --> 0x1fff0003e0 ==27323== to suppress, use: --max-stackframe=8388624 or greater 0 ==27323== ==27323== HEAP SUMMARY: ==27323== in use at exit: 0 bytes in 0 blocks ==27323== total heap usage: 1 allocs, 1 frees, 4,096 bytes allocated ==27323== ==27323== All heap blocks were freed -- no leaks are possible ==27323== ==27323== For counts of detected and suppressed errors, rerun with: -v ==27323== ERROR SUMMARY: 1048565 errors from 7 contexts (suppressed: 0 from 0)
Run GDB
gcc -std=c99 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o huge_array ./huge_array.c gnome-terminal -- gdb ./huge_array
gcc -std=c99 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o malloc_oob ./malloc_oob.c
echo 33 | valgrind ./malloc_oob 2>&1
==27315== Memcheck, a memory error detector ==27315== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==27315== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info ==27315== Command: ./malloc_oob ==27315== ==27315== Invalid read of size 4 ==27315== at 0x1088CF: main (malloc_oob.c:26) ==27315== Address 0x522f250 is 192 bytes inside an unallocated block of size 4,185,680 in arena "client" ==27315== How big? 0 ==27315== ==27315== HEAP SUMMARY: ==27315== in use at exit: 0 bytes in 0 blocks ==27315== total heap usage: 3 allocs, 3 frees, 8,324 bytes allocated ==27315== ==27315== All heap blocks were freed -- no leaks are possible ==27315== ==27315== For counts of detected and suppressed errors, rerun with: -v ==27315== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Run GDB
gcc -std=c99 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o malloc_oob ./malloc_oob.c gnome-terminal -- gdb ./malloc_oob
gcc -std=c99 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o malloc_uninit ./malloc_uninit.c
echo 33 | valgrind ./malloc_uninit 2>&1
==27303== Memcheck, a memory error detector ==27303== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==27303== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info ==27303== Command: ./malloc_uninit ==27303== ==27303== Conditional jump or move depends on uninitialised value(s) ==27303== at 0x4E988DA: vfprintf (vfprintf.c:1642) ==27303== by 0x4EA0F25: printf (printf.c:33) ==27303== by 0x108884: main (malloc_uninit.c:25) ==27303== ==27303== Use of uninitialised value of size 8 ==27303== at 0x4E9486B: _itoa_word (_itoa.c:179) ==27303== by 0x4E97F0D: vfprintf (vfprintf.c:1642) ==27303== by 0x4EA0F25: printf (printf.c:33) ==27303== by 0x108884: main (malloc_uninit.c:25) ==27303== ==27303== Conditional jump or move depends on uninitialised value(s) ==27303== at 0x4E94875: _itoa_word (_itoa.c:179) ==27303== by 0x4E97F0D: vfprintf (vfprintf.c:1642) ==27303== by 0x4EA0F25: printf (printf.c:33) ==27303== by 0x108884: main (malloc_uninit.c:25) ==27303== ==27303== Conditional jump or move depends on uninitialised value(s) ==27303== at 0x4E98014: vfprintf (vfprintf.c:1642) ==27303== by 0x4EA0F25: printf (printf.c:33) ==27303== by 0x108884: main (malloc_uninit.c:25) ==27303== ==27303== Conditional jump or move depends on uninitialised value(s) ==27303== at 0x4E98B4C: vfprintf (vfprintf.c:1642) ==27303== by 0x4EA0F25: printf (printf.c:33) ==27303== by 0x108884: main (malloc_uninit.c:25) ==27303== How big? 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ==27303== ==27303== HEAP SUMMARY: ==27303== in use at exit: 132 bytes in 1 blocks ==27303== total heap usage: 3 allocs, 2 frees, 8,324 bytes allocated ==27303== ==27303== LEAK SUMMARY: ==27303== definitely lost: 132 bytes in 1 blocks ==27303== indirectly lost: 0 bytes in 0 blocks ==27303== possibly lost: 0 bytes in 0 blocks ==27303== still reachable: 0 bytes in 0 blocks ==27303== suppressed: 0 bytes in 0 blocks ==27303== Rerun with --leak-check=full to see details of leaked memory ==27303== ==27303== For counts of detected and suppressed errors, rerun with: -v ==27303== Use --track-origins=yes to see where uninitialised values come from ==27303== ERROR SUMMARY: 165 errors from 5 contexts (suppressed: 0 from 0)
Run GDB
gcc -std=c99 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o malloc_uninit ./malloc_uninit.c gnome-terminal -- gdb ./malloc_uninit
gcc -std=c99 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o segv ./segv.c
echo 33 | valgrind ./segv 2>&1
==27291== Memcheck, a memory error detector ==27291== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==27291== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info ==27291== Command: ./segv ==27291== ==27291== Invalid read of size 4 ==27291== at 0x1088CF: main (segv.c:26) ==27291== Address 0x55ff9c0 is 3,999,792 bytes inside an unallocated block of size 4,185,680 in arena "client" ==27291== How big? 0 ==27291== ==27291== HEAP SUMMARY: ==27291== in use at exit: 0 bytes in 0 blocks ==27291== total heap usage: 3 allocs, 3 frees, 8,324 bytes allocated ==27291== ==27291== All heap blocks were freed -- no leaks are possible ==27291== ==27291== For counts of detected and suppressed errors, rerun with: -v ==27291== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Run GDB
gcc -std=c99 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o segv ./segv.c gnome-terminal -- gdb ./segv
gcc -std=c99 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o simple_uninit ./simple_uninit.c
echo 33 | valgrind ./simple_uninit 2>&1
==27279== Memcheck, a memory error detector ==27279== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==27279== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info ==27279== Command: ./simple_uninit ==27279== Enter an int: 33 ==27279== ==27279== HEAP SUMMARY: ==27279== in use at exit: 0 bytes in 0 blocks ==27279== total heap usage: 2 allocs, 2 frees, 8,192 bytes allocated ==27279== ==27279== All heap blocks were freed -- no leaks are possible ==27279== ==27279== For counts of detected and suppressed errors, rerun with: -v ==27279== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Run GDB
gcc -std=c99 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o simple_uninit ./simple_uninit.c gnome-terminal -- gdb ./simple_uninit
gcc -std=c99 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o stack ./stack.c
echo 33 | valgrind ./stack 2>&1
==27253== Memcheck, a memory error detector ==27253== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==27253== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info ==27253== Command: ./stack ==27253== Stack 0x522d040: 0 items starting at (nil) Enter some lines. Press ctrl-d (EOF) to end. Stack 0x522d040: 1 items starting at 0x522f1d0 Stack 0x522d040: 0 items starting at (nil) 33 ==27253== ==27253== HEAP SUMMARY: ==27253== in use at exit: 0 bytes in 1 blocks ==27253== total heap usage: 7 allocs, 6 frees, 8,456 bytes allocated ==27253== ==27253== LEAK SUMMARY: ==27253== definitely lost: 0 bytes in 1 blocks ==27253== indirectly lost: 0 bytes in 0 blocks ==27253== possibly lost: 0 bytes in 0 blocks ==27253== still reachable: 0 bytes in 0 blocks ==27253== suppressed: 0 bytes in 0 blocks ==27253== Rerun with --leak-check=full to see details of leaked memory ==27253== ==27253== For counts of detected and suppressed errors, rerun with: -v ==27253== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Run GDB
gcc -std=c99 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o stack ./stack.c gnome-terminal -- gdb ./stack
gcc -std=c99 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o stack_limit ./stack_limit.c
echo 33 | valgrind ./stack_limit 2>&1
Run GDB
gcc -std=c99 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o stack_limit ./stack_limit.c gnome-terminal -- gdb ./stack_limit
gcc -std=c99 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o use_after_free ./use_after_free.c
echo 33 | valgrind ./use_after_free 2>&1
Run GDB
gcc -std=c99 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o use_after_free ./use_after_free.c gnome-terminal -- gdb ./use_after_free
Run GDB
gcc -std=c99 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o infinite_recursion ./infinite_recursion.c gnome-terminal -- gdb ./infinite_recursion
Run valgrind
gcc -std=c99 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o infinite_recursion ./infinite_recursion.c echo "valgrind ./infinite_recursion ; read" > infinite_recursion.sh gnome-terminal -- bash infinite_recursion.sh
Valgrind results
depth: 261795 ==6818== Stack overflow in thread #1: can't grow stack to 0x1ffe801000 depth: 261796 ==6818== Stack overflow in thread #1: can't grow stack to 0x1ffe801000 depth: 261797 ==6818== Stack overflow in thread #1: can't grow stack to 0x1ffe801000 depth: 261798 ==6818== Stack overflow in thread #1: can't grow stack to 0x1ffe801000 depth: 261799 ==6818== Stack overflow in thread #1: can't grow stack to 0x1ffe801000
- Generator (ignore)
# look a bash for loop! for file in ./array_oob.c ./array_uninit.c ./bad_realloc.c ./bad_str.c ./double_free.c ./huge_array.c ./malloc_oob.c ./malloc_uninit.c ./segv.c ./simple_uninit.c ./stack.c ./stack_limit.c ./use_after_free.c #for file in ./array_oob.c ./array_uninit.c ./bad_realloc.c do exe=`basename -s .c $file` echo echo \*\*\*\* $file echo file:$file echo echo \#+BEGIN_SRC sh echo gcc -std=c99 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o $exe $file echo echo 33 \| valgrind ./$exe 2\>\&1 echo \#+END_SRC echo echo Run GDB echo \#+BEGIN_SRC sh echo gcc -std=c99 -pedantic -Wall -Wextra -ftrapv -ggdb3 -o $exe $file echo gnome-terminal -- gdb ./$exe echo \#+END_SRC done


@jorian @blackjok3r @webworker01 how about if we extend the 250,000 PIRATE airdrop acceptence until end of next month? More users will be able to participate.
And, extending the Logo submission date until 14th of October and we announce the winner of Logo competition.
The 10,000 PIRATE I offered can be used for signature campaign on BTCTalk forum. I need someone to manage the signature campaing for me. Anyone available to volunteer for this task?


Fresnel Zone Calculator
This Fresnel Zone and Antenna Height calculator helps you determine if you have "radio line of sight" between two distant points, or alternatively, how high you need to elevate either antenna to clear an obstruction. The calculator takes into account the earth's curvature and effects from refraction in the atmosphere.
If you have a very long RF link you need to take all these effects into account. For those links we encourage you to consider one of Afar Wireless Ethernet Bridges which can establish links in excess of 80 Km (50 miles).
The calculator is a Java applet which should work in your browser. Following the Fresnel Zone calculator you can find a short tutorial of RF propagation effects and the requirement for Fresnel zone clearance. If you have any comments or suggestions for improving this calculator send us a message.
Fresnel Zone Clearance and Antenna Height Calculator
Radio Line-of-sightAt UHF and microwave frequencies, when you deploy an RF link between
two distant sites you need to make sure you have "line of sight"
between the two antennas. But at these frequencies "line of sight"
does not simply mean that from one site you can "see" the other. When your distance exceeds, say, 5 miles (8 Km), you need to take into account the following factors:
- The curvature of the earth.
- Fresnel Zone clearance.
- Atmospheric refraction.
The figure below illustrates these concepts with an exaggerated representation of a long link. The following sections describe these effects.
Fresnel Zone Definition
The Fresnel zone is a long ellipsoid that stretches between the two antennas. The first Fresnel zone is such that the difference between the direct path (AB in the figure below) and an indirect path that touches a single point on the border of the Fresnel zone (ACB) is half the wavelength.
If a significant portion of the Fresnel zone is obstructed the receive-signal-strength at the receiving antenna can be greatly attenuated. A rule of thumb is that you need at least 60% of the first Fresnel zone clear of any obstructions in order for the radio wave propagation to behave as if it is in “free space”. "60% of the first Fresnel zone" means a narrower ellipsoid with a radius that is 60% of the radius of this first Fresnel zone.
Even though at 2.4 GHz half of the wavelength is only 2.4 inches (6.2 cm), at long distances the radius of this ellipsoid can be quite large. For example, with a link distance of 31 miles (50 Km) the radius of this (60%) ellipsoid at the mid-point is 77 ft (23 meters). You can use the calculator to compute this radius at any point in between the two antennas. You may also change the percent value of the first Fresnel zone you wish to clear.
Atmospheric RefractionUnder normal atmospheric conditions radio waves do not propagate in a straight line, they actually bend slightly downward. This is due to "refraction" in the atmosphere which affects radio waves propagating horizontally. To take this downward bending into account, we perform all the path calculations using a larger value for the earth radius, such that we can then consider the radio waves as propagating in a straight line.
In the Fresnel zone calculator you can change the earth radius multiplying factor (the "k factor") to take into account different atmospheric conditions. Under normal conditions the "k factor" is 4/3. However unusual weather conditions can cause significant changes to the refraction profile. For a high reliability link you may want to use a lower value for the k factor.
Equal Antenna Height Solution
For any given distance the Fresnel zone calculator displays the antenna heights (same at both ends) such that the Fresnel zone just clears the earth surface as shown in the figure below.
Different antenna heights
It is unusual that you would have both antennas at the same height, so
the calculator lets you enter different heights for the two end points (all heights are above sea-level; see "h1" and "h2" in the figure at the top).
The calculator computes the "minimum clearance point" which is the point in the path where the Fresnel zone is closest to the earth sea-level. It displays both the distance from site 1 and the clearance between the earth sea-level and the low boundary of the Fresnel zone. A negative clearance means the Fresnel zone overlaps with the earth profile.
Clearing an obstruction
The calculator allows you to quickly determine whether you have enough clearance above a particular obstruction in the RF path, or alternatively, how high you need to elevate your antennas to clear the obstruction.
For each potential obstruction in the path you need to know its distance from one of your end points and the height of the obstruction above sea-level. Drawing the path in “Google Earth ” is a quick way of identifying buildings or structures that lay in the direct path and finding their distance from the end points. You may need to use a topographic map, draw the line between the end points, and create an accurate terrain profile. If there are buildings or trees in the path you need to determine or estimate their height above the ground, and add it to the terrain elevation at those points.
For each of these potential obstruction points, enter its distance from site 1 and the height of the obstruction above sea level in the bottom left input “spinners” of the calculator. On the right hand side the calculator displays the vertical separation between the top of the obstruction and the bottom of the Fresnel Zone. If this value is negative you can use the antenna height spinners to increase the height of one or both antennas until that clearance becomes greater than zero.
RF Link Budget AnalysisIf you have 60% of the first Fresnel zone cleared of any obstructions then the RF propagation in your link will be similar to free space. Under those conditions you can use our RF link budget calculator to determine the expected receive signal strength and fade margin for your link.
|


work
カタカタカタカタ—
Sekai Project / Denpasoft
Lead Editor
• A Light in the Dark
• Girls in Glasses (18+)
• Miko no Kanata (18+)
• Re;Lord 2 (18+)
• ?????? (18+)
Assistant Editor
• NEKO-NIN exHeart (18+)
• NEKOPARA Vol.3 (18+)
• Re;Lord ~The Witch of Herfort and Stuffed Animals~ (18+)
Typesetting / Production (Samples: samples.pdf)
• CLANNAD: 10th Anniversary Art Book
• GATE: Where the JSDF Fought!
• Sakura Spirit
J-Novel Club
Lead Editor
• Der Werwolf: The Annals of Veight
• Infinite Stratos
Sol Press
Lead Editor
• Strongest Gamer: Let’s Play in Another World
Typesetting / Production
• Battle Divas: The Incorruptible Battle Blossom Princess
• Strongest Gamer: Let’s Play in Another World
Skills / Proficiencies
Languages
English (Native), Japanese (Intermediate)
Translation Tools
SDL Trados, Word, Excel, Google Docs
Production Tools
Photoshop, Illustrator, InDesign, Clip Studio Paint, Sigil, Aegisub
Development
HTML, CSS, PHP, Javascript, NodeJS


containsAll()
on java.util.List
.
The time complexity of this method call is O(n·m), where n is the number of elements in the list on which the method is called, and m is the number of elements in the collection passed to the method as a parameter. When the list is large, this can be an expensive operation.
The quick-fix wraps the list in new java.util.HashSet<>()
since the time required to create
java.util.HashSet
from java.util.List
and execute containsAll()
on
java.util.HashSet
is O(n+m).
Example:
public boolean check(List<String> list, Collection<String> collection) {
// O(n·m) complexity
return list.containsAll(collection);
}
After the quick-fix is applied:
public boolean check(List<String> list, Collection<String> collection) {
// O(n+m) complexity
return new HashSet<>(list).containsAll(collection);
}
New in 2022.1


---
layout: post
status: publish
published: true
title: "
Zambrano: Opening Day Starter to
8th Inning Set-up in 16 days.
"
author:
display_name: Corey Fineran
login: Corey
email<EMAIL_ADDRESS>url: ''
author_login: Corey
author_email<EMAIL_ADDRESS>wordpress_id: 2512
wordpress_url: http://ivyenvy.com/?p=2512
date: '2010-04-22 05:42:57 +0000'
date_gmt: '2010-04-22 11:42:57 +0000'
categories:
- Uncategorized
- Relief Pitching
- Starting Pitching
tags:
- Carlos Zambrano
- Jake Peavy
comments:
- id: 1246
author: H. Vaughn
author_email<EMAIL_ADDRESS>author_url: ''
date: '2010-04-24 07:07:03 +0000'
date_gmt: '2010-04-24 13:07:03 +0000'
content: "I think Cub nation is unnecessarily overwrought about this move, as if
using Z to shore up the pen for awhile is akin to taking a Corvette offroad. \r\n\r\nTwo
points:\r\n\r\n1) Middle relief is a huge problem on this club.\r\n\r\nLets survey
the headlines of our losses thus far after the Opening Day travesty, m'kay?\r\n\r\nBraves
Rally in Eighth to Take First Two From Cubs\r\nReds Overtake Cubs Late on Stubbs
Grand Slam\r\nReds Rally Late to Beat Cubs Despite Leake's Seven Walks\r\nBrewers
Avoid Sweep. . . (Samardzia and Grabow again)\r\n(Offense Fails Against Astros)\r\n(Pagan
Tie-Breaking Homer in 7th - Russell and Samardiza)\r\n(Shutout by Mets)\r\n(Offense
held to two runs by Mets)\r\n\r\nPretty easy to see that if the Cubs were a patient
bleeding out on a stretcher, two serrated carving knives labeled Grabow and Samardzija
would be lying nearby in the weeds. Soriano, Soto-Wilkins and Hendry would be
charged as accessories. \r\n\r\n2) Z is a pretty good pitcher and he can always
go back to the rotation when the Cubs find a fungible reliever under a rock.\r\n\r\nThis
move enhances their chances of winning until Silva goes back to being a pumpkin
and has no downside."
---
Text message from Paul - April 21st, 12:22pm
They should move Carlos to the pen when Lilly comes back.
I can't hang with about 3/4 of what Paul says about the Cubs, but he has an incredible track record with this stuff. Last year, when I hadn't heard a single person say anything about it (and about a week before it happened), Paul predicted that Jake Peavy would go to the White Sox.
I am not going to state my full opinion on the Zambrano situation in a post. I'm not in favor, and I'm having trouble organizing my thoughts. I just can't seem to pull it all together, or even get past "It's so stupid!" This is not one of those moves that I considered enough to have a fully formed opinion.
There will be a group of us Ivy Envy writers getting together this weekend for the podcast, so watch for that. I am not sure there will be any other topic discussed, especially if we can get Paul to show up and defend his stance.
If you have a good take on the situation, leave a comment here or e-mail us and we'll read it on the podcast. The e-mail address is: podcast@ivyenvy.com


Explore Datasets
With supporting text below as a natural lead-in to additional content.
Star DatasetWith supporting text below as a natural lead-in to additional content.
Star DatasetWith supporting text below as a natural lead-in to additional content.
Star DatasetWith supporting text below as a natural lead-in to additional content.
Star Dataset


snow camouflage nivalis change cover weasels {border-style climate colour weasel px;} winter #ffffff;} mismatch moult moulting different days model Białowieża models predation individuals brown data mortality number Forest Mustela morphs study temperatures conditions experimental plasticity vulgaris ambient distribution factor px; used white years {font-family (Table , = ., S). animals area coat duration font-size increased limited mean morph permanent population seasonal session (LM, Sci. Zub autumn average caused changes changing climatic decreased detected double; effect fitness increasing pelage predator present progress p = ., selective species spring time weather (Fig. Fig. However, K.Z. Proc. Table affect analysed background beginning border-color border-width collected conditions. decreasing detection dorsal higher increase linear long main mammals mismatch, natural numbers observations occur phenotypic pressure recorded results significantly sites solid; variables variation warming {font-style {font-weight ./s--- Biol. Buteo Camouflage Commons Creative Ecol. February National Nature Weasels abundance according adaptation body bold camera completely courier; cover, em; experiments field fixed following fox future hares high important material meters period, potential pt;} rate revealed share significant snow-free studies trapping traps vulgaris.


THtmlViewer, TFrameViewer, and TFrameBrowser components
property SelText: WideString;
Read only and run time only. The SelText property returns the selected text in string form. For TFrameViewer.or TFrameBrowser, this would be the selection in the currently active frame.
See Also


{% extends "base.html" %} {% block title %}Image Search Abstraction Layer{% endblock %} {% block content %}
User stories:
- I can get the image URLs, alt text and page urls for a set of images relating to a given search string.
- I can paginate through the responses by adding a ?offset=2 parameter to the URL.
- I can get a list of the most recently submitted search strings.
http://localhost:8000/api/imagesearch/lolcats?offset=2
http://localhost:8000/api/latest/imagesearch


Fast Path: English-speaking working life orientation and job-search coaching course Galimatias Concept Oy Ab2020


Settings
LRS endpoint:
LRS Basic Key:
LRS Basic Secret:
Registration:
Learner name:
Learner unique key:
Time's up!
Start again.
Time:
Points:
Acc: