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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | /* this is a "find" program: usage: find -options pattern -x shows the lines without the pattern instead of the one that actually contains it. -n print line numbers */ main(int argc, char *argv[]) { while(--argc > 0) printf((argc > 1) ? "%s " : "%s", *++argv); printf("\n"); return 0; } #endif #include <stdio.h> #include "mylib.c" main(int argc, char *argv[]) { char line[MAXLEN]; long lineno = 0; int c, exept = 0, number = 0, found = 0; while(--argc > 0 && (*++argv)[0] == '-') while(c = *++argv[0]) switch(c) { case 'x': exept = 1; break; case 'n': number = 1; break; default: printf("find: illegal option\n"); argc = 0; found = -1; break; } if(argc != 1) printf("Usage : find -x -n pattern\n"); else while(getline(line, MAXLEN) > 0) { lineno++; if((strstr(line, *argv) != NULL) != exept) { if(number) printf("%ld:", lineno); printf("%s", line); found++; } } return found; } |
ratchetfreak
C has many mistakes in its history, defining NULL as 0 (an int) instead of a special ident like nullptr (which is what you should use in C++) is one of them.
ratchetfreak
Why C++ doesn't define NULL as nullptr is because idiot programmers used NULL as the 0 constant, most probably to avoid "magic number" warnings and nullptr doesn't convert to int implicitly so a #define NULL nullptr would break the C compatibility.
mrmixer
Since you're not including string.h, I guess you're implementing strstr in mylib.c.
ratchetfreak
C has many mistakes in its history, defining NULL as 0 (an int) instead of a special ident like nullptr (which is what you should use in C++) is one of them.
Why C++ doesn't define NULL as nullptr is because idiot programmers used NULL as the 0 constant, most probably to avoid "magic number" warnings and nullptr doesn't convert to int implicitly so a #define NULL nullptr would break the C compatibility.
Randy Gaul
For example I have my own opinion: C defining NULL as ((void*)0) was great because anyone can go lookup the exact definition of what NULL is and see the definition in terms of elementary expressions, integers and type-casting. This helps make it obvious that pointers are, on the assembly level, just numbers like any other integer. The concept of a pointer is just a semantic construct. If we look at nullptr, what exactly is it? Well, we don't know without doing a google search or looking up some kind of specification. Suddenly nullptr becomes a little more abstracted when nullptr is used.
1 2 3 4 5 6 7 8 9 | int i = 0; char * p1 = 0; uint16_t * p2 = 0; uint32_t * p4 = 0; ++i; // i = 1 ++p1; // p1 = 1 ++p2; // p2 = 2 ++p4; // p4 = 4 |
1 2 3 4 5 6 7 | union{ void* ptr; size_t i; } un; un.i = 0; assert(un.ptr == NULL); |
cmuratori
Yes, what I am saying is stronger: 0 _must_ be a reserved address meaning "null pointer", always, in all cases except for the like one singular exception in kernel mode code where you're actually talking about the base of physical memory for some required reason. This is because it is crucial that memset(0) work to clear things, including pointers, and giving up that functionality is much too costly in practice IMO.
- Casey