From a86eb3f07efc2f5dc383f0b8612574b740d81023 Mon Sep 17 00:00:00 2001 From: Lilian Besson Date: Sat, 30 Jan 2021 15:25:22 +0100 Subject: Update c.html.markdown Just add a few explanations where I thought details were missing --- c.html.markdown | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) (limited to 'c.html.markdown') diff --git a/c.html.markdown b/c.html.markdown index a57be1dc..55e300e8 100644 --- a/c.html.markdown +++ b/c.html.markdown @@ -224,9 +224,15 @@ int main (int argc, char** argv) (float)i1 / i2; // => 0.5f i1 / (double)i2; // => 0.5 // Same with double f1 / f2; // => 0.5, plus or minus epsilon + // Floating-point numbers and calculations are not exact + // for instance it is not giving mathematically correct results + (0.1 + 0.1 + 0.1) != 0.3; // => 1 (true) + // and it is NOT associative + 1 + (1e123 - 1e123) != (1 + 1e123) - 1e123; // => 1 (true) + // this notation is scientific notations for numbers: 1e123 = 1*10^123 - // Modulo is there as well + // Modulo is there as well, but be careful if arguments are negative 11 % 3; // => 2 // Comparison operators are probably familiar, but @@ -236,12 +242,12 @@ int main (int argc, char** argv) // operators always yield 0 or 1.) 3 == 2; // => 0 (false) 3 != 2; // => 1 (true) - 3 > 2; // => 1 - 3 < 2; // => 0 + 3 > 2; // => 1 + 3 < 2; // => 0 2 <= 2; // => 1 2 >= 2; // => 1 - // C is not Python - comparisons don't chain. + // C is not Python - comparisons do NOT chain. // Warning: The line below will compile, but it means `(0 < a) < 2`. // This expression is always true, because (0 < a) could be either 1 or 0. // In this case it's 1, because (0 < 1). @@ -349,26 +355,28 @@ int main (int argc, char** argv) break; } /* - using "goto" in C + Using "goto" in C */ typedef enum { false, true } bool; // for C don't have bool as data type before C99 :( bool disaster = false; int i, j; - for(i=0;i<100;++i) - for(j=0;j<100;++j) + for(i=0; i<100; ++i) + for(j=0; j<100; ++j) { if((i + j) >= 150) disaster = true; if(disaster) - goto error; + goto error; // exit both for loops } - error : + error: // this is a label that you can "jump" to with "goto error;" printf("Error occurred at i = %d & j = %d.\n", i, j); /* - https://ideone.com/GuPhd6 - this will print out "Error occurred at i = 51 & j = 99." + https://ideone.com/GuPhd6 + this will print out "Error occurred at i = 51 & j = 99." */ + /* it is generally considered bad practice to do so, except if */ + /* you really know what you are doing */ /////////////////////////////////////// // Typecasting @@ -741,6 +749,7 @@ typedef void (*my_fnp_type)(char *); // Order of Evaluation /////////////////////////////////////// +// From top to bottom, top is has higher precedence //---------------------------------------------------// // Operators | Associativity // //---------------------------------------------------// @@ -783,8 +792,8 @@ as the C file. /* included into files that include this header. */ #include -/* Like c source files macros can be defined in headers and used in files */ -/* that include this header file. */ +/* Like for c source files, macros can be defined in headers */ +/* and used in files that include this header file. */ #define EXAMPLE_NAME "Dennis Ritchie" /* Function macros can also be defined. */ -- cgit v1.2.3 From 7616948a8eff29af4f24780565beb0ae9775377e Mon Sep 17 00:00:00 2001 From: Lilian Besson Date: Sun, 31 Jan 2021 13:56:45 +0100 Subject: Update c.html.markdown Following reviews from @menelion --- c.html.markdown | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'c.html.markdown') diff --git a/c.html.markdown b/c.html.markdown index 55e300e8..ff396d21 100644 --- a/c.html.markdown +++ b/c.html.markdown @@ -233,7 +233,9 @@ int main (int argc, char** argv) // this notation is scientific notations for numbers: 1e123 = 1*10^123 // Modulo is there as well, but be careful if arguments are negative - 11 % 3; // => 2 + 11 % 3; // => 2 as 11 = 2 + 3*x (x=3) + (-11) % 3; // => -2, as one would expect + 11 % (-3); // => 2 and not -2, and it's quite counter intuitive // Comparison operators are probably familiar, but // there is no Boolean type in C. We use ints instead. @@ -375,8 +377,11 @@ int main (int argc, char** argv) https://ideone.com/GuPhd6 this will print out "Error occurred at i = 51 & j = 99." */ - /* it is generally considered bad practice to do so, except if */ - /* you really know what you are doing */ + /* + it is generally considered bad practice to do so, except if + you really know what you are doing. See + https://en.wikipedia.org/wiki/Spaghetti_code#Meaning + */ /////////////////////////////////////// // Typecasting @@ -749,12 +754,12 @@ typedef void (*my_fnp_type)(char *); // Order of Evaluation /////////////////////////////////////// -// From top to bottom, top is has higher precedence +// From top to bottom, top has higher precedence //---------------------------------------------------// // Operators | Associativity // //---------------------------------------------------// // () [] -> . | left to right // -// ! ~ ++ -- + = *(type)sizeof | right to left // +// ! ~ ++ -- + = *(type) sizeof | right to left // // * / % | left to right // // + - | left to right // // << >> | left to right // @@ -832,7 +837,7 @@ Best to find yourself a copy of [K&R, aka "The C Programming Language"](https:// It is *the* book about C, written by Dennis Ritchie, the creator of C, and Brian Kernighan. Be careful, though - it's ancient and it contains some inaccuracies (well, ideas that are not considered good anymore) or now-changed practices. -Another good resource is [Learn C The Hard Way](http://learncodethehardway.org/c/). +Another good resource is [Learn C The Hard Way](http://learncodethehardway.org/c/) (not free). If you have a question, read the [compl.lang.c Frequently Asked Questions](http://c-faq.com). @@ -842,4 +847,4 @@ Readable code is better than clever code and fast code. For a good, sane coding Other than that, Google is your friend. -[1] [Why isn't sizeof for a struct equal to the sum of sizeof of each member?](http://stackoverflow.com/questions/119123/why-isnt-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member) +[1] [Why isn't sizeof for a struct equal to the sum of sizeof of each member?](https://stackoverflow.com/questions/119123/why-isnt-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member) -- cgit v1.2.3 From 99ddf8fec686a137586e7a4cdf068b7d3c438cfc Mon Sep 17 00:00:00 2001 From: awschult002 <73046001+awschult002@users.noreply.github.com> Date: Tue, 24 Aug 2021 15:57:49 -0400 Subject: [c/en] mostly word clarification and extra descriptions (#4222) * Adds extra clarity to enum value assignment. The previous statement shows only 1 way to declare enums, and it happens that they specify a starting value. I clarify that a starting value is not necessary and that all enum value could contain user specified values. * Added clarity to `includes` section. specified that angle brackets are for system libraries and not just standard libs. I also added an example of relative paths in the local include statements. * Added more clarity for function prototyping and main return vals. I cleaned up some formatting; then added some clarity to how function prototyping works, as well as recommend techniques. * Fixed the mention of character sizes. they are not always 1 byte * Added clarity about floating point arithmetic. The previous comments on floating points made it feel like there was something broken with doing comparison and arithmetics with floating point types. I added clarity about how floats are stored in memory and why they seem to behave strangly when used in arithmetic expressions. * reworded boolean stuff for better clarity on _Bool type in C99 * Adds not about binary assignment * Added clarity for value roll over * Added section on multiple return values. C doesnt allow returning of multiple values, so i added a section on returning multiple values through pointers. * added section break for printing special characters * fix typo Co-authored-by: Andre Polykanine * fix typos Co-authored-by: Andre Polykanine * fix markdown syntax Co-authored-by: Andre Polykanine * fix markdown syntax Co-authored-by: Andre Polykanine * fix markdown syntax Co-authored-by: Andre Polykanine * reword with better english Co-authored-by: Andre Polykanine * reword with better english Co-authored-by: Andre Polykanine Co-authored-by: Andre Polykanine --- c.html.markdown | 83 ++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 67 insertions(+), 16 deletions(-) (limited to 'c.html.markdown') diff --git a/c.html.markdown b/c.html.markdown index ff396d21..7405c7ab 100644 --- a/c.html.markdown +++ b/c.html.markdown @@ -46,31 +46,47 @@ Multi-line comments don't nest /* Be careful */ // comment ends on this line... // Enumeration constants are also ways to declare constants. // All statements must end with a semicolon -enum days {SUN = 1, MON, TUE, WED, THU, FRI, SAT}; +enum days {SUN, MON, TUE, WED, THU, FRI, SAT}; +// SUN gets 0, MON gets 1, TUE gets 2, etc. + +// Enumeration values can also be specified +enum days {SUN = 1, MON, TUE, WED = 99, THU, FRI, SAT}; // MON gets 2 automatically, TUE gets 3, etc. +// WED get 99, THU gets 100, FRI gets 101, etc. // Import headers with #include #include #include #include -// (File names between are headers from the C standard library.) -// For your own headers, use double quotes instead of angle brackets: -//#include "my_header.h" +// File names between tell the compiler to look in your system +// libraries for the headers. +// For your own headers, use double quotes instead of angle brackets, and +// provide the path: +#include "my_header.h" // local file +#include "../my_lib/my_lib_header.h" //relative path // Declare function signatures in advance in a .h file, or at the top of // your .c file. void function_1(); int function_2(void); -// Must declare a 'function prototype' before main() when functions occur after -// your main() function. +// At a minimum, you must declare a 'function prototype' before its use in any function. +// Normally, prototypes are placed at the top of a file before any function definition. int add_two_ints(int x1, int x2); // function prototype // although `int add_two_ints(int, int);` is also valid (no need to name the args), // it is recommended to name arguments in the prototype as well for easier inspection -// Your program's entry point is a function called -// main with an integer return type. +// Function prototypes are not necessary if the function definition comes before +// any other function that calls that function. However, it's standard practice to +// always add the function prototype to a header file (*.h) and then #include that +// file at the top. This prevents any issues where a function might be called +// before the compiler knows of its existence, while also giving the developer a +// clean header file to share with the rest of the project. + +// Your program's entry point is a function called "main". The return type can +// be anything, however most operating systems expect a return type of `int` for +// error code processing. int main(void) { // your program } @@ -96,13 +112,14 @@ int main (int argc, char** argv) // For the sake of the tutorial, variables are declared dynamically under // C99-compliant standards. - // ints are usually 4 bytes + // ints are usually 4 bytes (use the `sizeof` operator to check) int x_int = 0; - // shorts are usually 2 bytes + // shorts are usually 2 bytes (use the `sizeof` operator to check) short x_short = 0; - // chars are guaranteed to be 1 byte + // chars are defined as the smallest addressable unit for a processor. + // This is usually 1 byte, but for some systems it can be more (ex. for TMS320 from TI it's 2 bytes). char x_char = 0; char y_char = 'y'; // Char literals are quoted with '' @@ -225,13 +242,22 @@ int main (int argc, char** argv) i1 / (double)i2; // => 0.5 // Same with double f1 / f2; // => 0.5, plus or minus epsilon - // Floating-point numbers and calculations are not exact - // for instance it is not giving mathematically correct results + // Floating-point numbers are defined by IEEE 754, thus cannot store perfectly + // exact values. For instance, the following does not produce expected results + // because 0.1 might actually be 0.099999999999 insided the computer, and 0.3 + // might be stored as 0.300000000001. (0.1 + 0.1 + 0.1) != 0.3; // => 1 (true) - // and it is NOT associative + // and it is NOT associative due to reasons mentioned above. 1 + (1e123 - 1e123) != (1 + 1e123) - 1e123; // => 1 (true) // this notation is scientific notations for numbers: 1e123 = 1*10^123 + // It is important to note that most all systems have used IEEE 754 to + // represent floating points. Even python, used for scientific computing, + // eventually calls C which uses IEEE 754. It is mentioned this way not to + // indicate that this is a poor implementation, but instead as a warning + // that when doing floating point comparisons, a little bit of error (epsilon) + // needs to be considered. + // Modulo is there as well, but be careful if arguments are negative 11 % 3; // => 2 as 11 = 2 + 3*x (x=3) (-11) % 3; // => -2, as one would expect @@ -239,7 +265,7 @@ int main (int argc, char** argv) // Comparison operators are probably familiar, but // there is no Boolean type in C. We use ints instead. - // (Or _Bool or bool in C99.) + // (C99 introduced the _Bool type provided in stdbool.h) // 0 is false, anything else is true. (The comparison // operators always yield 0 or 1.) 3 == 2; // => 0 (false) @@ -391,13 +417,16 @@ int main (int argc, char** argv) // if you want (with some constraints). int x_hex = 0x01; // You can assign vars with hex literals + // binary is not in the standard, but allowed by some + // compilers (x_bin = 0b0010010110) // Casting between types will attempt to preserve their numeric values printf("%d\n", x_hex); // => Prints 1 printf("%d\n", (short) x_hex); // => Prints 1 printf("%d\n", (char) x_hex); // => Prints 1 - // Types will overflow without warning + // If you assign a value greater than a types max val, it will rollover + // without warning. printf("%d\n", (unsigned char) 257); // => 1 (Max char = 255 if char is 8 bits long) // For determining the max value of a `char`, a `signed char` and an `unsigned char`, @@ -588,6 +617,24 @@ printf("first: %d\nsecond: %d\n", first, second); // values will be swapped */ +// Return multiple values. +// C does not allow for returning multiple values with the return statement. If +// you would like to return multiple values, then the caller must pass in the +// variables where they would like the returned values to go. These variables must +// be passed in as pointers such that the function can modify them. +int return_multiple( int *array_of_3, int *ret1, int *ret2, int *ret3) +{ + if(array_of_3 == NULL) + return 0; //return error code (false) + + //de-reference the pointer so we modify its value + *ret1 = array_of_3[0]; + *ret2 = array_of_3[1]; + *ret3 = array_of_3[2]; + + return 1; //return error code (true) +} + /* With regards to arrays, they will always be passed to functions as pointers. Even if you statically allocate an array like `arr[10]`, @@ -716,6 +763,10 @@ typedef void (*my_fnp_type)(char *); // my_fnp_type f; +///////////////////////////// +// Printing characters with printf() +///////////////////////////// + //Special characters: /* '\a'; // alert (bell) character -- cgit v1.2.3 From 6a0b4aee8771bbb992b9ddcbfc3823ecc974bdd3 Mon Sep 17 00:00:00 2001 From: krotera <01101011@tuta.io> Date: Mon, 3 Jan 2022 09:44:49 -0700 Subject: [c/en] clarity, errata, and grammar in array section (#4102) * [c/en] clarity, errata, and grammar in array section - [x] I solemnly swear that this is all original content of which I am the original author - [x] Pull request title is prepended with `[language/lang-code]` (example `[python/fr-fr]` or `[java/en]`) - [x] Pull request touches only one file (or a set of logically related files with similar changes made) - [x] Content changes are aimed at *intermediate to experienced programmers* (this is a poor format for explaining fundamental programming concepts) - [x] If you've changed any part of the YAML Frontmatter, make sure it is formatted according to [CONTRIBUTING.md](https://github.com/adambard/learnxinyminutes-docs/blob/master/CONTRIBUTING.markdown) - [x] Yes, I have double-checked quotes and field names! * Overlooked type uniformity * Improve 80 col alignment and clarify loop control var declaration * Remove agrammatical comma * Mention typedef in struct declaration --- c.html.markdown | 53 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 17 deletions(-) (limited to 'c.html.markdown') diff --git a/c.html.markdown b/c.html.markdown index 7405c7ab..90b5ed2d 100644 --- a/c.html.markdown +++ b/c.html.markdown @@ -162,19 +162,25 @@ int main (int argc, char** argv) int my_int_array[20]; // This array occupies 4 * 20 = 80 bytes // (assuming 4-byte words) - // You can initialize an array to 0 thusly: - char my_array[20] = {0}; + // You can initialize an array of twenty ints that all equal 0 thusly: + int my_array[20] = {0}; // where the "{0}" part is called an "array initializer". - // NOTE that you get away without explicitly declaring the size of the array, - // IF you initialize the array on the same line. So, the following declaration - // is equivalent: - char my_array[] = {0}; - // BUT, then you have to evaluate the size of the array at run-time, like this: + // All elements (if any) past the ones in the initializer are initialized to 0: + int my_array[5] = {1, 2}; + // So my_array now has five elements, all but the first two of which are 0: + // [1, 2, 0, 0, 0] + // NOTE that you get away without explicitly declaring the size + // of the array IF you initialize the array on the same line: + int my_array[] = {0}; + // NOTE that, when not declaring the size, the size of the array is the number + // of elements in the initializer. With "{0}", my_array is now of size one: [0] + // To evaluate the size of the array at run-time, divide its byte size by the + // byte size of its element type: size_t my_array_size = sizeof(my_array) / sizeof(my_array[0]); - // WARNING If you adopt this approach, you should evaluate the size *before* - // you begin passing the array to function (see later discussion), because - // arrays get "downgraded" to raw pointers when they are passed to functions - // (so the statement above will produce the wrong result inside the function). + // WARNING You should evaluate the size *before* you begin passing the array + // to functions (see later discussion) because arrays get "downgraded" to + // raw pointers when they are passed to functions (so the statement above + // will produce the wrong result inside the function). // Indexing an array is like other languages -- or, // rather, other languages are like C @@ -572,7 +578,8 @@ the function are copies of the original arguments (except arrays). Anything you do to the arguments in the function do not change the value of the original argument where the function was called. -Use pointers if you need to edit the original argument values. +Use pointers if you need to edit the original argument values (arrays are always +passed in as pointers). Example: in-place string reversal */ @@ -583,9 +590,11 @@ void str_reverse(char *str_in) char tmp; size_t ii = 0; size_t len = strlen(str_in); // `strlen()` is part of the c standard library - // NOTE: length returned by `strlen` DOESN'T include the - // terminating NULL byte ('\0') - for (ii = 0; ii < len / 2; ii++) { // in C99 you can directly declare type of `ii` here + // NOTE: length returned by `strlen` DOESN'T + // include the terminating NULL byte ('\0') + // in C99 and newer versions, you can directly declare loop control variables + // in the loop's parentheses. e.g., `for (size_t ii = 0; ...` + for (ii = 0; ii < len / 2; ii++) { tmp = str_in[ii]; str_in[ii] = str_in[len - ii - 1]; // ii-th char from end str_in[len - ii - 1] = tmp; @@ -700,7 +709,7 @@ struct rectangle { void function_1() { - struct rectangle my_rec; + struct rectangle my_rec = { 1, 2 }; // Fields can be initialized immediately // Access struct members with . my_rec.width = 10; @@ -724,6 +733,16 @@ int area(rect r) return r.width * r.height; } +// Typedefs can also be defined right during struct definition +typedef struct { + int width; + int height; +} rect; +// Like before, doing this means one can type +rect r; +// instead of having to type +struct rectangle r; + // if you have large structs, you can pass them "by pointer" to avoid copying // the whole struct: int areaptr(const rect *r) @@ -876,7 +895,7 @@ enum traffic_light_state {GREEN, YELLOW, RED}; Node createLinkedList(int *vals, int len); /* Beyond the above elements, other definitions should be left to a C source */ -/* file. Excessive includes or definitions should, also not be contained in */ +/* file. Excessive includes or definitions should also not be contained in */ /* a header file but instead put into separate headers or a C file. */ #endif /* End of the if precompiler directive. */ -- cgit v1.2.3