This commit is contained in:
Adam 2013-08-16 09:44:22 -07:00
parent 5be20756e0
commit 8aa0ab6068
7 changed files with 239 additions and 238 deletions

View File

@ -1,11 +1,9 @@
--- ---
- name: c language: c
- category: language filename: learnc.c
- language: c contributors:
- filename: learnc.c - ["Adam Bard", "http://adambard.com/"]
- contributors: - ["Árpád Goretity", "http://twitter.com/H2CO3_iOS"]
- [Adam Bard](http://adambard.com/)
- [Árpád Goretity](http://twitter.com/H2CO3_iOS)
--- ---
@ -27,17 +25,10 @@ Multi-line comments look like this. They work in C89 as well.
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
// file names between <angle brackets> are headers from the C standard library. // (File names between <angle brackets> are headers from the C standard library.)
// They are searched for by the preprocessor in the system include paths
// (usually /usr/lib on Unices, can be controlled with the -I<dir> option if you are using GCC or clang.)
// For your own headers, use double quotes instead of angle brackets: // For your own headers, use double quotes instead of angle brackets:
#include "my_header.h" #include "my_header.h"
// The C preprocessor introduces an almost fully-featured macro language. It's useful, but
// it can be confusing (and what's even worse, it can be misused). Read the
// Wikipedia article on the C preprocessor for further information:
// http://en.wikipedia.org/wiki/C_preprocessor
// Declare function signatures in advance in a .h file, or at the top of // Declare function signatures in advance in a .h file, or at the top of
// your .c file. // your .c file.
void function_1(); void function_1();
@ -50,132 +41,117 @@ int main() {
// %d is an integer, \n is a newline // %d is an integer, \n is a newline
printf("%d\n", 0); // => Prints 0 printf("%d\n", 0); // => Prints 0
// All statements must end with a semicolon // All statements must end with a semicolon
/////////////////////////////////////// ///////////////////////////////////////
// Types // Types
/////////////////////////////////////// ///////////////////////////////////////
// You have to declare variables before using them. A variable declaration
// requires you to specify its type; a variable's type determines its size
// in bytes.
// ints are usually 4 bytes // ints are usually 4 bytes
int x_int = 0; int x_int = 0;
// shorts are usually 2 bytes // shorts are usually 2 bytes
short x_short = 0; short x_short = 0;
// chars are guaranteed to be 1 byte // chars are guaranteed to be 1 byte
char x_char = 0; char x_char = 0;
char y_char = 'y'; // Char literals are quoted with '' char y_char = 'y'; // Char literals are quoted with ''
// longs are often 4 to 8 bytes; long longs are guaranteed to be at least // longs are often 4 to 8 bytes; long longs are guaranteed to be at least
// 64 bits // 64 bits
long x_long = 0; long x_long = 0;
long long x_long_long = 0; long long x_long_long = 0;
// floats are usually 32-bit floating point numbers // floats are usually 32-bit floating point numbers
float x_float = 0.0; float x_float = 0.0;
// doubles are usually 64-bit floating-point numbers // doubles are usually 64-bit floating-point numbers
double x_double = 0.0; double x_double = 0.0;
// Integral types may be unsigned. This means they can't be negative, but // Integral types may be unsigned.
// the maximum value of an unsigned variable is greater than the maximum
// signed value of the same size.
unsigned char ux_char;
unsigned short ux_short; unsigned short ux_short;
unsigned int ux_int; unsigned int ux_int;
unsigned long long ux_long_long; unsigned long long ux_long_long;
// Other than char, which is always 1 byte (but not necessarily 8 bits!), // sizeof(T) gives you the size of a variable with type T in bytes
// these types vary in size depending on your machine and compiler. // sizeof(obj) yields the size of the expression (variable, literal, etc.).
// sizeof(T) gives you the size of a variable with type T in
// bytes so you can express the size of these types in a portable way.
// sizeof(obj) yields the size of an actual expression (variable, literal, etc.).
// For example,
printf("%zu\n", sizeof(int)); // => 4 (on most machines with 4-byte words) printf("%zu\n", sizeof(int)); // => 4 (on most machines with 4-byte words)
// It's worth noting that if the argument of the `sizeof` operator is not a type but an expression, // If the argument of the `sizeof` operator an expression, then its argument
// then its argument is not evaluated except VLAs (see below). Also, `sizeof()` is an operator, not a function, // is not evaluated (except VLAs (see below)).
// furthermore, the value it yields is a compile-time constant (except when used on VLAs, again.) // The value it yields in this case is a compile-time constant.
int a = 1; int a = 1;
size_t size = sizeof(a++); // a++ is not evaluated size_t size = sizeof(a++); // a++ is not evaluated
printf("sizeof(a++) = %zu where a = %d\n", size, a); printf("sizeof(a++) = %zu where a = %d\n", size, a);
// the above code prints "sizeof(a++) = 4 where a = 1" (on a usual 32-bit architecture) // prints "sizeof(a++) = 4 where a = 1" (on a 32-bit architecture)
// Arrays must be initialized with a concrete size. // Arrays must be initialized with a concrete size.
char my_char_array[20]; // This array occupies 1 * 20 = 20 bytes char my_char_array[20]; // This array occupies 1 * 20 = 20 bytes
int my_int_array[20]; // This array occupies 4 * 20 = 80 bytes int my_int_array[20]; // This array occupies 4 * 20 = 80 bytes
// (assuming 4-byte words) // (assuming 4-byte words)
// You can initialize an array to 0 thusly: // You can initialize an array to 0 thusly:
char my_array[20] = {0}; char my_array[20] = {0};
// Indexing an array is like other languages -- or, // Indexing an array is like other languages -- or,
// rather, other languages are like C // rather, other languages are like C
my_array[0]; // => 0 my_array[0]; // => 0
// Arrays are mutable; it's just memory! // Arrays are mutable; it's just memory!
my_array[1] = 2; my_array[1] = 2;
printf("%d\n", my_array[1]); // => 2 printf("%d\n", my_array[1]); // => 2
// In C99 (and as an optional feature in C11), variable-length arrays (VLAs) can be declared as well. // In C99 (and as an optional feature in C11), variable-length arrays (VLAs)
// The size of such an array need not be a compile time constant: // can be declared as well. The size of such an array need not be a compile
// time constant:
printf("Enter the array size: "); // ask the user for an array size printf("Enter the array size: "); // ask the user for an array size
char buf[0x100]; char buf[0x100];
fgets(buf, sizeof buf, stdin); fgets(buf, sizeof buf, stdin);
size_t size = strtoul(buf, NULL, 10); // strtoul parses a string to an unsigned integer
// strtoul parses a string to an unsigned integer
size_t size = strtoul(buf, NULL, 10);
int var_length_array[size]; // declare the VLA int var_length_array[size]; // declare the VLA
printf("sizeof array = %zu\n", sizeof var_length_array); printf("sizeof array = %zu\n", sizeof var_length_array);
// A possible outcome of this program may be: // A possible outcome of this program may be:
Enter the array size: 10 // > Enter the array size: 10
sizeof array = 40 // > sizeof array = 40
// Strings are just arrays of chars terminated by a NUL (0x00) byte, // Strings are just arrays of chars terminated by a NUL (0x00) byte,
// represented in strings as the special character '\0'. // represented in strings as the special character '\0'.
// (We don't have to include the NUL byte in string literals; the compiler // (We don't have to include the NUL byte in string literals; the compiler
// inserts it at the end of the array for us.) // inserts it at the end of the array for us.)
char a_string[20] = "This is a string"; char a_string[20] = "This is a string";
printf("%s\n", a_string); // %s formats a string printf("%s\n", a_string); // %s formats a string
/*
You may have noticed that a_string is only 16 chars long.
Char #17 is the NUL byte.
Chars #18, 19 and 20 are 0 as well - if an initializer list (in this case, the string literal)
has less elements than the array it is initializing, then excess array elements are implicitly
initialized to zero. This is why int ar[10] = { 0 } works as expected intuitively.
*/
printf("%d\n", a_string[16]); // => 0 printf("%d\n", a_string[16]); // => 0
// i.e., byte #17 is 0 (as are 18, 19, and 20)
// So string literals are strings enclosed within double quotes, but if we have characters
// between single quotes, that's a character literal. // If we have characters between single quotes, that's a character literal.
// It's of type `int`, and *not* `char` (for historical reasons). // It's of type `int`, and *not* `char` (for historical reasons).
int cha = 'a'; // fine int cha = 'a'; // fine
char chb = 'a'; // fine too (implicit conversion from int to char - truncation) char chb = 'a'; // fine too (implicit conversion from int to char)
/////////////////////////////////////// ///////////////////////////////////////
// Operators // Operators
/////////////////////////////////////// ///////////////////////////////////////
int i1 = 1, i2 = 2; // Shorthand for multiple declaration int i1 = 1, i2 = 2; // Shorthand for multiple declaration
float f1 = 1.0, f2 = 2.0; float f1 = 1.0, f2 = 2.0;
// Arithmetic is straightforward // Arithmetic is straightforward
i1 + i2; // => 3 i1 + i2; // => 3
i2 - i1; // => 1 i2 - i1; // => 1
i2 * i1; // => 2 i2 * i1; // => 2
i1 / i2; // => 0 (0.5, but truncated towards 0) i1 / i2; // => 0 (0.5, but truncated towards 0)
f1 / f2; // => 0.5, plus or minus epsilon - floating-point numbers and calculations are not exact f1 / f2; // => 0.5, plus or minus epsilon
// Floating-point numbers and calculations are not exact
// Modulo is there as well // Modulo is there as well
11 % 3; // => 2 11 % 3; // => 2
// Comparison operators are probably familiar, but // Comparison operators are probably familiar, but
// there is no boolean type in c. We use ints instead. // there is no boolean type in c. We use ints instead.
// (Or _Bool or bool in C99.) // (Or _Bool or bool in C99.)
@ -187,14 +163,14 @@ int main() {
3 < 2; // => 0 3 < 2; // => 0
2 <= 2; // => 1 2 <= 2; // => 1
2 >= 2; // => 1 2 >= 2; // => 1
// C is not Python - comparisons don't chain. // C is not Python - comparisons don't chain.
int a = 1; int a = 1;
// WRONG: // WRONG:
int between_0_and_2 = 0 < a < 2; int between_0_and_2 = 0 < a < 2;
// Correct: // Correct:
int between_0_and_2 = 0 < a && a < 2; int between_0_and_2 = 0 < a && a < 2;
// Logic works on ints // Logic works on ints
!3; // => 0 (Logical not) !3; // => 0 (Logical not)
!0; // => 1 !0; // => 1
@ -202,7 +178,7 @@ int main() {
0 && 1; // => 0 0 && 1; // => 0
0 || 1; // => 1 (Logical or) 0 || 1; // => 1 (Logical or)
0 || 0; // => 0 0 || 0; // => 0
// Bitwise operators! // Bitwise operators!
~0x0F; // => 0xF0 (bitwise negation, "1's complement") ~0x0F; // => 0xF0 (bitwise negation, "1's complement")
0x0F & 0xF0; // => 0x00 (bitwise AND) 0x0F & 0xF0; // => 0x00 (bitwise AND)
@ -210,17 +186,17 @@ int main() {
0x04 ^ 0x0F; // => 0x0B (bitwise XOR) 0x04 ^ 0x0F; // => 0x0B (bitwise XOR)
0x01 << 1; // => 0x02 (bitwise left shift (by 1)) 0x01 << 1; // => 0x02 (bitwise left shift (by 1))
0x02 >> 1; // => 0x01 (bitwise right shift (by 1)) 0x02 >> 1; // => 0x01 (bitwise right shift (by 1))
// Be careful when shifting signed integers - the following are all undefined behavior: // Be careful when shifting signed integers - the following are undefined:
// - shifting into the sign bit of a signed integer (int a = 1 << 32) // - shifting into the sign bit of a signed integer (int a = 1 << 32)
// - left-shifting a negative number (int a = -1 << 2) // - left-shifting a negative number (int a = -1 << 2)
// - shifting by an offset which is more than or equal to the width of the type of the LHS: // - shifting by an offset which is >= the width of the type of the LHS:
// int a = 1 << 32; // UB if int is 32 bits wide // int a = 1 << 32; // UB if int is 32 bits wide
/////////////////////////////////////// ///////////////////////////////////////
// Control Structures // Control Structures
/////////////////////////////////////// ///////////////////////////////////////
if (0) { if (0) {
printf("I am never run\n"); printf("I am never run\n");
} else if (0) { } else if (0) {
@ -228,36 +204,38 @@ int main() {
} else { } else {
printf("I print\n"); printf("I print\n");
} }
// While loops exist // While loops exist
int ii = 0; int ii = 0;
while (ii < 10) { while (ii < 10) {
printf("%d, ", ii++); // ii++ increments ii in-place, after yielding its value ("postincrement"). printf("%d, ", ii++); // ii++ increments ii in-place
// after yielding its value ("postincrement").
} // => prints "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " } // => prints "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "
printf("\n"); printf("\n");
int kk = 0; int kk = 0;
do { do {
printf("%d, ", kk); printf("%d, ", kk);
} while (++kk < 10); // ++kk increments kk in-place, and yields the already incremented value ("preincrement") } while (++kk < 10); // ++kk increments kk in-place, and yields
// the already incremented value ("preincrement")
// => prints "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " // => prints "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "
printf("\n"); printf("\n");
// For loops too // For loops too
int jj; int jj;
for (jj=0; jj < 10; jj++) { for (jj=0; jj < 10; jj++) {
printf("%d, ", jj); printf("%d, ", jj);
} // => prints "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " } // => prints "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "
printf("\n"); printf("\n");
// branching with multiple choices: switch() // branching with multiple choices: switch()
switch (some_integral_expression) { switch (some_integral_expression) {
case 0: // labels need to be integral *constant* epxressions case 0: // labels need to be integral *constant* epxressions
do_stuff(); do_stuff();
break; // if you don't break, control flow falls over labels - you usually don't want that. break; // if you don't break, control flow falls over labels
case 1: case 1:
do_something_else(); do_something_else();
break; break;
@ -267,73 +245,74 @@ int main() {
exit(-1); exit(-1);
break; break;
} }
/////////////////////////////////////// ///////////////////////////////////////
// Typecasting // Typecasting
/////////////////////////////////////// ///////////////////////////////////////
// Every value in C has a type, but you can cast one value into another type // Every value in C has a type, but you can cast one value into another type
// if you want (with some constraints). // if you want (with some constraints).
int x_hex = 0x01; // You can assign vars with hex literals int x_hex = 0x01; // You can assign vars with hex literals
// Casting between types will attempt to preserve their numeric values // Casting between types will attempt to preserve their numeric values
printf("%d\n", x_hex); // => Prints 1 printf("%d\n", x_hex); // => Prints 1
printf("%d\n", (short) x_hex); // => Prints 1 printf("%d\n", (short) x_hex); // => Prints 1
printf("%d\n", (char) x_hex); // => Prints 1 printf("%d\n", (char) x_hex); // => Prints 1
// Types will overflow without warning // Types will overflow without warning
printf("%d\n", (unsigned char) 257); // => 1 (Max char = 255 if char is 8 bits long) printf("%d\n", (unsigned char) 257); // => 1 (Max char = 255 if char is 8 bits long)
// printf("%d\n", (unsigned char) 257); would be undefined behavior - `char' is usually signed
// on most modern systems, and signed integer overflow invokes UB. // For determining the max value of a `char`, a `signed char` and an `unisigned char`,
// Also, for determining the maximal value of a `char`, a `signed char` and an `unisigned char`,
// respectively, use the CHAR_MAX, SCHAR_MAX and UCHAR_MAX macros from <limits.h> // respectively, use the CHAR_MAX, SCHAR_MAX and UCHAR_MAX macros from <limits.h>
// Integral types can be cast to floating-point types, and vice-versa. // Integral types can be cast to floating-point types, and vice-versa.
printf("%f\n", (float)100); // %f formats a float printf("%f\n", (float)100); // %f formats a float
printf("%lf\n", (double)100); // %lf formats a double printf("%lf\n", (double)100); // %lf formats a double
printf("%d\n", (char)100.0); printf("%d\n", (char)100.0);
/////////////////////////////////////// ///////////////////////////////////////
// Pointers // Pointers
/////////////////////////////////////// ///////////////////////////////////////
// A pointer is a variable declared to store a memory address. Its declaration will // A pointer is a variable declared to store a memory address. Its declaration will
// also tell you the type of data it points to. You can retrieve the memory address // also tell you the type of data it points to. You can retrieve the memory address
// of your variables, then mess with them. // of your variables, then mess with them.
int x = 0; int x = 0;
printf("%p\n", (void *)&x); // Use & to retrieve the address of a variable printf("%p\n", (void *)&x); // Use & to retrieve the address of a variable
// (%p formats an object pointer of type void *) // (%p formats an object pointer of type void *)
// => Prints some address in memory; // => Prints some address in memory;
// Pointers start with * in their declaration // Pointers start with * in their declaration
int *px, not_a_pointer; // px is a pointer to an int int *px, not_a_pointer; // px is a pointer to an int
px = &x; // Stores the address of x in px px = &x; // Stores the address of x in px
printf("%p\n", (void *)px); // => Prints some address in memory printf("%p\n", (void *)px); // => Prints some address in memory
printf("%zu, %zu\n", sizeof(px), sizeof(not_a_pointer)); printf("%zu, %zu\n", sizeof(px), sizeof(not_a_pointer));
// => Prints "8, 4" on a typical 64-bit system // => Prints "8, 4" on a typical 64-bit system
// To retreive the value at the address a pointer is pointing to, // To retreive the value at the address a pointer is pointing to,
// put * in front to de-reference it. // put * in front to de-reference it.
// Note: yes, it may be confusing that '*' is used for _both_ declaring a pointer and dereferencing it. // Note: yes, it may be confusing that '*' is used for _both_ declaring a
printf("%d\n", *px); // => Prints 0, the value of x, which is what px is pointing to the address of // pointer and dereferencing it.
printf("%d\n", *px); // => Prints 0, the value of x
// You can also change the value the pointer is pointing to. // You can also change the value the pointer is pointing to.
// We'll have to wrap the de-reference in parenthesis because // We'll have to wrap the de-reference in parenthesis because
// ++ has a higher precedence than *. // ++ has a higher precedence than *.
(*px)++; // Increment the value px is pointing to by 1 (*px)++; // Increment the value px is pointing to by 1
printf("%d\n", *px); // => Prints 1 printf("%d\n", *px); // => Prints 1
printf("%d\n", x); // => Prints 1 printf("%d\n", x); // => Prints 1
int x_array[20]; // Arrays are a good way to allocate a contiguous block of memory // Arrays are a good way to allocate a contiguous block of memory
int x_array[20];
int xx; int xx;
for (xx = 0; xx < 20; xx++) { for (xx = 0; xx < 20; xx++) {
x_array[xx] = 20 - xx; x_array[xx] = 20 - xx;
} // Initialize x_array to 20, 19, 18,... 2, 1 } // Initialize x_array to 20, 19, 18,... 2, 1
// Declare a pointer of type int and initialize it to point to x_array // Declare a pointer of type int and initialize it to point to x_array
int* x_ptr = x_array; int* x_ptr = x_array;
// x_ptr now points to the first element in the array (the integer 20). // x_ptr now points to the first element in the array (the integer 20).
@ -342,50 +321,52 @@ int main() {
// it decays into (implicitly converted to) a pointer. // it decays into (implicitly converted to) a pointer.
// Exceptions: when the array is the argument of the `&` (address-od) operator: // Exceptions: when the array is the argument of the `&` (address-od) operator:
int arr[10]; int arr[10];
int (*ptr_to_arr)[10] = &arr; // &arr is NOT of type `int *`! It's of type "pointer to array" (of ten `int`s). int (*ptr_to_arr)[10] = &arr; // &arr is NOT of type `int *`!
// It's of type "pointer to array" (of ten `int`s).
// or when the array is a string literal used for initializing a char array: // or when the array is a string literal used for initializing a char array:
char arr[] = "foobarbazquirk"; char arr[] = "foobarbazquirk";
// or when it's the argument of the `sizeof` or `alignof` operator: // or when it's the argument of the `sizeof` or `alignof` operator:
int arr[10]; int arr[10];
int *ptr = arr; // equivalent with int *ptr = &arr[0]; int *ptr = arr; // equivalent with int *ptr = &arr[0];
printf("%zu %zu\n", sizeof arr, sizeof ptr); // probably prints "40, 4" or "40, 8" printf("%zu %zu\n", sizeof arr, sizeof ptr); // probably prints "40, 4" or "40, 8"
// Pointers are incremented and decremented based on their type // Pointers are incremented and decremented based on their type
// (this is called pointer arithmetic) // (this is called pointer arithmetic)
printf("%d\n", *(x_ptr + 1)); // => Prints 19 printf("%d\n", *(x_ptr + 1)); // => Prints 19
printf("%d\n", x_array[1]); // => Prints 19 printf("%d\n", x_array[1]); // => Prints 19
// You can also dynamically allocate contiguous blocks of memory with the // You can also dynamically allocate contiguous blocks of memory with the
// standard library function malloc, which takes one argument of type size_t // standard library function malloc, which takes one argument of type size_t
// representing the number of bytes to allocate (usually from the heap, although this // representing the number of bytes to allocate (usually from the heap, although this
// may not be true on e. g. embedded systems - the C standard says nothing about it). // may not be true on e. g. embedded systems - the C standard says nothing about it).
int *my_ptr = malloc(sizeof(*my_ptr) * 20); int *my_ptr = malloc(sizeof(*my_ptr) * 20);
for (xx = 0; xx < 20; xx++) { for (xx = 0; xx < 20; xx++) {
*(my_ptr + xx) = 20 - xx; // my_ptr[xx] = 20-xx would also work here, and it's also more readable *(my_ptr + xx) = 20 - xx; // my_ptr[xx] = 20-xx
} // Initialize memory to 20, 19, 18, 17... 2, 1 (as ints) } // Initialize memory to 20, 19, 18, 17... 2, 1 (as ints)
// Dereferencing memory that you haven't allocated gives // Dereferencing memory that you haven't allocated gives
// "unpredictable results" - the program is said to invoke "undefined behavior" // "unpredictable results" - the program is said to invoke "undefined behavior"
printf("%d\n", *(my_ptr + 21)); // => Prints who-knows-what? It may even crash. printf("%d\n", *(my_ptr + 21)); // => Prints who-knows-what? It may even crash.
// When you're done with a malloc'd block of memory, you need to free it, // When you're done with a malloc'd block of memory, you need to free it,
// or else no one else can use it until your program terminates // or else no one else can use it until your program terminates
// (this is called a "memory leak"): // (this is called a "memory leak"):
free(my_ptr); free(my_ptr);
// Strings are arrays of char, but they are usually represented as a // Strings are arrays of char, but they are usually represented as a
// pointer-to-char (which is a pointer to the first element of the array). // pointer-to-char (which is a pointer to the first element of the array).
// It's good practice to use `const char *' when referring to a string literal, // It's good practice to use `const char *' when referring to a string literal,
// since string literals shall not be modified (i. e. "foo"[0] = 'a' is ILLEGAL.) // since string literals shall not be modified (i. e. "foo"[0] = 'a' is ILLEGAL.)
const char *my_str = "This is my very own string literal"; const char *my_str = "This is my very own string literal";
printf("%c\n", *my_str); // => 'T' printf("%c\n", *my_str); // => 'T'
// This is not the case if the string is an array (potentially initialized with a string literal) // This is not the case if the string is an array
// (potentially initialized with a string literal)
// that resides in writable memory, as in: // that resides in writable memory, as in:
char foo[] = "foo"; char foo[] = "foo";
foo[0] = 'a'; // this is legal, foo now contains "aoo" foo[0] = 'a'; // this is legal, foo now contains "aoo"
function_1(); function_1();
} // end main function } // end main function
@ -435,17 +416,17 @@ printf("%s\n", c); // => ".tset a si sihT"
typedef int my_type; typedef int my_type;
my_type my_type_var = 0; my_type my_type_var = 0;
// Structs are just collections of data, the members are allocated sequentially, in the order they are written: // Structs are just collections of data, the members are allocated sequentially,
// in the order they are written:
struct rectangle { struct rectangle {
int width; int width;
int height; int height;
}; };
// it's generally not true that sizeof(struct rectangle) == sizeof(int) + sizeof(int) due to // It's not generally true that
// potential padding between the structure members (this is for alignment reasons. Probably won't // sizeof(struct rectangle) == sizeof(int) + sizeof(int)
// happen if all members are of the same type, but watch out! // due to potential padding between the structure members (this is for alignment
// See http://stackoverflow.com/questions/119123/why-isnt-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member // reasons). [1]
// for further information.
void function_1() void function_1()
{ {
@ -473,7 +454,8 @@ int area(rect r)
return r.width * r.height; return r.width * r.height;
} }
// if you have large structs, you can pass them "by pointer" to avoid copying the whole struct: // if you have large structs, you can pass them "by pointer" to avoid copying
// the whole struct:
int area(const rect *r) int area(const rect *r)
{ {
return r->width * r->height; return r->width * r->height;
@ -527,3 +509,5 @@ Readable code is better than clever code and fast code. For a good, sane coding
[Linux kernel coding stlye](https://www.kernel.org/doc/Documentation/CodingStyle). [Linux kernel coding stlye](https://www.kernel.org/doc/Documentation/CodingStyle).
Other than that, Google is your friend. Other than that, Google is your friend.
[1] http://stackoverflow.com/questions/119123/why-isnt-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member

View File

@ -1,5 +1,6 @@
--- ---
language: java language: java
filename: java-kr.java
category: language category: language
contributors: contributors:
- ["Jake Prather", "http://github.com/JakeHP"] - ["Jake Prather", "http://github.com/JakeHP"]
@ -26,7 +27,8 @@ import java.util.ArrayList;
// java.security 패키지 안에 있는 모든 클래스를 임포트합니다. // java.security 패키지 안에 있는 모든 클래스를 임포트합니다.
import java.security.*; import java.security.*;
// 각 .java 파일에는 공용(public) 클래스가 들어 있으며, 클래스의 이름은 파일명과 동일합니다. // 각 .java 파일에는 공용(public) 클래스가 들어 있으며, 클래스의 이름은
// 파일명과 동일합니다.
public class LearnJava { public class LearnJava {
// 프로그램에는 반드시 진입점 역할을 하는 main 메서드가 하나 있어야 합니다. // 프로그램에는 반드시 진입점 역할을 하는 main 메서드가 하나 있어야 합니다.
@ -253,8 +255,8 @@ public class LearnJava {
// String // String
// 형변환 // 형변환
// 자바 객채 또한 형변환할 수 있으며, 이와 관련해서 알아야 할 세부사항이 많을뿐더러 // 자바 객채 또한 형변환할 수 있으며, 이와 관련해서 알아야 할 세부사항이
// 다소 중급 수준에 해당하는 개념들도 다뤄야 합니다. // 많을뿐더러 다소 중급 수준에 해당하는 개념들도 다뤄야 합니다.
// 이와 관련된 사항은 아래 링크를 참고하세요. // 이와 관련된 사항은 아래 링크를 참고하세요.
// http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html // http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html
@ -403,4 +405,4 @@ class PennyFarthing extends Bicycle {
* [제네릭(Generics)](http://docs.oracle.com/javase/tutorial/java/generics/index.html) * [제네릭(Generics)](http://docs.oracle.com/javase/tutorial/java/generics/index.html)
* [자바 코딩 관례(Java Code Conventions)](http://www.oracle.com/technetwork/java/codeconv-138413.html) * [자바 코딩 관례(Java Code Conventions)](http://www.oracle.com/technetwork/java/codeconv-138413.html)

View File

@ -1,5 +1,6 @@
--- ---
language: ruby language: ruby
lang: br-pt
filename: learnruby.rb filename: learnruby.rb
contributors: contributors:
- ["Bruno Henrique - Garu", "http://garulab.com"] - ["Bruno Henrique - Garu", "http://garulab.com"]
@ -98,9 +99,10 @@ caminho_para_a_raiz_do_projeto = '/bom/nome/'
caminho = '/nome/ruim/' caminho = '/nome/ruim/'
# Símbolos (são objetos) # Símbolos (são objetos)
# Símbolos são imutáveis, são constantes reutilizáveis representadadas internamente por um # Símbolos são imutáveis, são constantes reutilizáveis representadadas
# valor inteiro. Eles são frequentemente usados no lugar de strings para transmitir com eficiência os valores # internamente por um valor inteiro. Eles são frequentemente usados no
# específicos e significativos # lugar de strings para transmitir com eficiência os valores específicos
# e significativos
:pendente.class #=> Symbol :pendente.class #=> Symbol

View File

@ -4,7 +4,7 @@ filename: learnclojure-ru.clj
contributors: contributors:
- ["Adam Bard", "http://adambard.com/"] - ["Adam Bard", "http://adambard.com/"]
- ["Alexey Pirogov", "http://twitter.com/alex_pir"] - ["Alexey Pirogov", "http://twitter.com/alex_pir"]
lang: ru-ru
--- ---
Clojure, это представитель семейства Lisp-подобных языков, разработанный Clojure, это представитель семейства Lisp-подобных языков, разработанный

View File

@ -88,7 +88,8 @@ $unescaped = 'This just contains a slash and a t: \t';
// Заключайте переменные в фигурные скобки если это необходимо // Заключайте переменные в фигурные скобки если это необходимо
$money = "I have $${number} in the bank."; $money = "I have $${number} in the bank.";
// Начиная с PHP 5.3, синтаксис nowdocs может использоваться для неинтерполированного многострочного текста // Начиная с PHP 5.3, синтаксис nowdocs может использоваться для
// неинтерполированного многострочного текста
$nowdoc = <<<'END' $nowdoc = <<<'END'
Multi line Multi line
string string
@ -210,11 +211,13 @@ echo $integer + $integer; // => 2
$string = '1'; $string = '1';
echo $string + $string; // => 2 (строка превращается в число) echo $string + $string; // => 2 (строка превращается в число)
// Выводится 0 по той причине, что оператор + не может привести строку 'one' к числовому типу // Выводится 0 по той причине, что оператор + не может привести строку 'one' к
// числовому типу
$string = 'one'; $string = 'one';
echo $string + $string; // => 0 echo $string + $string; // => 0
// Приведение типов (type casting) может быть использовано для преобразование переменной в другой тип // Приведение типов (type casting) может быть использовано для преобразование
// переменной в другой тип
$boolean = (boolean) 1; // => true $boolean = (boolean) 1; // => true
$zero = 0; $zero = 0;
@ -429,10 +432,11 @@ return 'Anything you like.';
// Эти функции могут также возвращать значения. // Эти функции могут также возвращать значения.
$value = include 'my-include.php'; $value = include 'my-include.php';
// Имена файлов содержат их путь в файловой системе, или если передано просто имя файла, // Имена файлов содержат их путь в файловой системе, или если передано просто
// PHP обращается к директиве include_path. Если файл не найден в include_path, предпринимается // имя файла, PHP обращается к директиве include_path. Если файл не найден в
// попытка поиска в папке, где выполняется скрипт или в текущей рабочей директории. // include_path, предпринимается попытка поиска в папке, где выполняется скрипт
// Если не в одном из этих мест файл не найден - выдается ошибка // или в текущей рабочей директории. Если не в одном из этих мест файл не
// найден - выдается ошибка
/* */ /* */
/******************************** /********************************

View File

@ -1,5 +1,6 @@
--- ---
language: python language: python
lang: ru-ru
contributors: contributors:
- ["Yury Timofeev", "http://twitter.com/gagar1n"] - ["Yury Timofeev", "http://twitter.com/gagar1n"]
filename: learnpython-ru.py filename: learnpython-ru.py
@ -219,7 +220,8 @@ filled_dict["four"] # KeyError
# Чтобы избежать этого, используйте метод get # Чтобы избежать этого, используйте метод get
filled_dict.get("one") #=> 1 filled_dict.get("one") #=> 1
filled_dict.get("four") #=> None filled_dict.get("four") #=> None
# Метод get также принимает аргумент default, значение которого будет возвращено при отсутствии указанного ключа # Метод get также принимает аргумент default, значение которого будет
# возвращено при отсутствии указанного ключа
filled_dict.get("one", 4) #=> 1 filled_dict.get("one", 4) #=> 1
filled_dict.get("four", 4) #=> 4 filled_dict.get("four", 4) #=> 4
@ -314,7 +316,9 @@ try:
# Для выбора ошибки используется raise # Для выбора ошибки используется raise
raise IndexError("Это IndexError") raise IndexError("Это IndexError")
except IndexError as e: except IndexError as e:
pass # pass это просто отсутствие оператора. Обычно здесь происходит восстановление от ошибки. # pass это просто отсутствие оператора. Обычно здесь происходит
# восстановление от ошибки.
pass
#################################################### ####################################################

View File

@ -29,7 +29,8 @@ import (
"strconv" // 字符串转换 "strconv" // 字符串转换
) )
//函数声明Main是程序执行的入口。不管你喜欢还是不喜欢反正G就用了花括号来包住函数体。 // 函数声明Main是程序执行的入口。
// 不管你喜欢还是不喜欢反正G就用了花括号来包住函数体。
func main() { func main() {
// 往标准输出打印一行。 // 往标准输出打印一行。
// 用包名fmt限制打印函数。 // 用包名fmt限制打印函数。
@ -65,10 +66,10 @@ func learnTypes() {
can include line breaks.` // 同样是String类型 can include line breaks.` // 同样是String类型
// 非ascii字符。Go使用UTF-8编码。 // 非ascii字符。Go使用UTF-8编码。
g := 'Σ' // rune类型uint32的别名使用UTF-8编码 g := 'Σ' // rune类型uint32的别名使用UTF-8编码
f := 3.14195 // float64类型IEEE-754 64位浮点数 f := 3.14195 // float64类型IEEE-754 64位浮点数
c := 3 + 4i // complex128类型内部使用两个float64表示 c := 3 + 4i // complex128类型内部使用两个float64表示
// Var变量可以直接初始化。 // Var变量可以直接初始化。
var u uint = 7 // unsigned 无符号变量但是实现依赖int型变量的长度 var u uint = 7 // unsigned 无符号变量但是实现依赖int型变量的长度
@ -99,9 +100,9 @@ can include line breaks.` // 同样是String类型
// 下划线 _ 可以使你“使用”一个变量,但是丢弃它的值。 // 下划线 _ 可以使你“使用”一个变量,但是丢弃它的值。
_,_,_,_,_,_,_,_,_ = s2, g, f, u, pi, n, a3, s4, bs _,_,_,_,_,_,_,_,_ = s2, g, f, u, pi, n, a3, s4, bs
// 输出变量 // 输出变量
fmt.Println(s, c, a4, s3, d2, m) fmt.Println(s, c, a4, s3, d2, m)
learnFlowControl() // 回到流程控制 learnFlowControl() // 回到流程控制
} }
// Go全面支持垃圾回收。Go有指针但是不支持指针运算。 // Go全面支持垃圾回收。Go有指针但是不支持指针运算。
@ -117,155 +118,159 @@ func learnMemory() (p, q *int) {
} }
func expensiveComputation() int { func expensiveComputation() int {
return 1e6 return 1e6
} }
func learnFlowControl() { func learnFlowControl() {
// If需要花括号括号就免了 // If需要花括号括号就免了
if true { if true {
fmt.Println("told ya") fmt.Println("told ya")
} }
// 用go fmt 命令可以帮你格式化代码,所以不用怕被人吐槽代码风格了,也不用容忍被人的代码风格。 // 用go fmt 命令可以帮你格式化代码,所以不用怕被人吐槽代码风格了,
if false { // 也不用容忍被人的代码风格。
// pout if false {
} else { // pout
// gloat } else {
} // gloat
}
// 如果太多嵌套的if语句推荐使用switch // 如果太多嵌套的if语句推荐使用switch
x := 1 x := 1
switch x { switch x {
case 0: case 0:
case 1: case 1:
// 隐式调用break语句匹配上一个即停止 // 隐式调用break语句匹配上一个即停止
case 2: case 2:
// 不会运行 // 不会运行
} }
// 和if一样for也不用括号 // 和if一样for也不用括号
for x := 0; x < 3; x++ { // ++ 自增 for x := 0; x < 3; x++ { // ++ 自增
fmt.Println("iteration", x) fmt.Println("iteration", x)
} }
// x在这里还是1。为什么 // x在这里还是1。为什么
// for 是go里唯一的循环关键字不过它有很多变种 // for 是go里唯一的循环关键字不过它有很多变种
for { // 无限循环 for { // 无限循环
break // 骗你的 break // 骗你的
continue // 不会运行的 continue // 不会运行的
} }
// 和for一样if中的:=先给y赋值然后再和x作比较。 // 和for一样if中的:=先给y赋值然后再和x作比较。
if y := expensiveComputation(); y > x { if y := expensiveComputation(); y > x {
x = y x = y
} }
// 闭包函数 // 闭包函数
xBig := func() bool { xBig := func() bool {
return x > 100 // x是上面声明的变量引用 return x > 100 // x是上面声明的变量引用
} }
fmt.Println("xBig:", xBig()) // true 上面把y赋给x了 fmt.Println("xBig:", xBig()) // true 上面把y赋给x了
x /= 1e5 // x变成10 x /= 1e5 // x变成10
fmt.Println("xBig:", xBig()) // 现在是false fmt.Println("xBig:", xBig()) // 现在是false
// 当你需要goto的时候你会爱死它的 // 当你需要goto的时候你会爱死它的
goto love goto love
love: love:
learnInterfaces() // 好东西来了! learnInterfaces() // 好东西来了!
} }
// 定义Stringer为一个接口类型有一个方法String // 定义Stringer为一个接口类型有一个方法String
type Stringer interface { type Stringer interface {
String() string String() string
} }
// 定义pair为一个结构体有x和y两个int型变量。 // 定义pair为一个结构体有x和y两个int型变量。
type pair struct { type pair struct {
x, y int x, y int
} }
// 定义pair类型的方法实现Stringer接口。 // 定义pair类型的方法实现Stringer接口。
func (p pair) String() string { // p被叫做“接收器” func (p pair) String() string { // p被叫做“接收器”
// Sprintf是fmt包中的另一个公有函数。 // Sprintf是fmt包中的另一个公有函数。
// 用 . 调用p中的元素。 // 用 . 调用p中的元素。
return fmt.Sprintf("(%d, %d)", p.x, p.y) return fmt.Sprintf("(%d, %d)", p.x, p.y)
} }
func learnInterfaces() { func learnInterfaces() {
// 花括号用来定义结构体变量,:=在这里将一个结构体变量赋值给p。 // 花括号用来定义结构体变量,:=在这里将一个结构体变量赋值给p。
p := pair{3, 4} p := pair{3, 4}
fmt.Println(p.String()) // 调用pair类型p的String方法 fmt.Println(p.String()) // 调用pair类型p的String方法
var i Stringer // 声明i为Stringer接口类型 var i Stringer // 声明i为Stringer接口类型
i = p // 有效因为p实现了Stringer接口类似java中的塑型 i = p // 有效因为p实现了Stringer接口类似java中的塑型
// 调用i的String方法输出和上面一样 // 调用i的String方法输出和上面一样
fmt.Println(i.String()) fmt.Println(i.String())
// fmt包中的Println函数向对象要它们的string输出实现了String方法就可以这样使用了。类似java中的序列化 // fmt包中的Println函数向对象要它们的string输出实现了String方法就可以这样使用了。
fmt.Println(p) // 输出和上面一样自动调用String函数。 // 类似java中的序列化
fmt.Println(i) // 输出和上面一样。 fmt.Println(p) // 输出和上面一样自动调用String函数。
fmt.Println(i) // 输出和上面一样。
learnErrorHandling() learnErrorHandling()
} }
func learnErrorHandling() { func learnErrorHandling() {
// ", ok"用来判断有没有正常工作 // ", ok"用来判断有没有正常工作
m := map[int]string{3: "three", 4: "four"} m := map[int]string{3: "three", 4: "four"}
if x, ok := m[1]; !ok { // ok 为false因为m中没有1 if x, ok := m[1]; !ok { // ok 为false因为m中没有1
fmt.Println("no one there") fmt.Println("no one there")
} else { } else {
fmt.Print(x) // 如果x在map中的话x就是那个值喽。 fmt.Print(x) // 如果x在map中的话x就是那个值喽。
} }
// 错误可不只是ok它还可以给出关于问题的更多细节。 // 错误可不只是ok它还可以给出关于问题的更多细节。
if _, err := strconv.Atoi("non-int"); err != nil { // _ discards value if _, err := strconv.Atoi("non-int"); err != nil { // _ discards value
// 输出"strconv.ParseInt: parsing "non-int": invalid syntax" // 输出"strconv.ParseInt: parsing "non-int": invalid syntax"
fmt.Println(err) fmt.Println(err)
} }
// 待会再说接口吧。同时, // 待会再说接口吧。同时,
learnConcurrency() learnConcurrency()
} }
// c是channel类型一个并发安全的通信对象。 // c是channel类型一个并发安全的通信对象。
func inc(i int, c chan int) { func inc(i int, c chan int) {
c <- i + 1 // <-把右边的发送到左边的channel c <- i + 1 // <-把右边的发送到左边的channel
} }
// 我们将用inc函数来并发地增加一些数字。 // 我们将用inc函数来并发地增加一些数字。
func learnConcurrency() { func learnConcurrency() {
// 用make来声明一个slicemake会分配和初始化slicemap和channel。 // 用make来声明一个slicemake会分配和初始化slicemap和channel。
c := make(chan int) c := make(chan int)
// 用go关键字开始三个并发的goroutine如果机器支持的话还可能是并行执行。三个都被发送到同一个channel。 // 用go关键字开始三个并发的goroutine如果机器支持的话还可能是并行执行。
go inc(0, c) // go is a statement that starts a new goroutine. // 三个都被发送到同一个channel。
go inc(10, c) go inc(0, c) // go is a statement that starts a new goroutine.
go inc(-805, c) go inc(10, c)
go inc(-805, c)
// 从channel中独处结果并打印。 // 从channel中独处结果并打印。
// 打印出什么东西是不可预知的。 // 打印出什么东西是不可预知的。
fmt.Println(<-c, <-c, <-c) // channel在右边的时候<-是接收操作 fmt.Println(<-c, <-c, <-c) // channel在右边的时候<-是接收操作
cs := make(chan string) // 操作string的channel cs := make(chan string) // 操作string的channel
cc := make(chan chan string) // 操作channel的channel cc := make(chan chan string) // 操作channel的channel
go func() { c <- 84 }() // 开始一个goroutine来发送一个新的数字 go func() { c <- 84 }() // 开始一个goroutine来发送一个新的数字
go func() { cs <- "wordy" }() // 发送给cs go func() { cs <- "wordy" }() // 发送给cs
// Select类似于switch但是每个case包括一个channel操作。它随机选择一个准备好通讯的case。 // Select类似于switch但是每个case包括一个channel操作。
select { // 它随机选择一个准备好通讯的case。
case i := <-c: // 从channel接收的值可以赋给其他变量 select {
fmt.Println("it's a", i) case i := <-c: // 从channel接收的值可以赋给其他变量
case <-cs: // 或者直接丢弃 fmt.Println("it's a", i)
fmt.Println("it's a string") case <-cs: // 或者直接丢弃
case <-cc: // 空的还没作好通讯的准备 fmt.Println("it's a string")
fmt.Println("didn't happen.") case <-cc: // 空的还没作好通讯的准备
} fmt.Println("didn't happen.")
}
// 上面c或者cs的值被取到其中一个goroutine结束另外一个保持阻塞。 // 上面c或者cs的值被取到其中一个goroutine结束另外一个保持阻塞。
learnWebProgramming() // Go很适合web编程我知道你也想学 learnWebProgramming() // Go很适合web编程我知道你也想学
} }
// http包中的一个简单的函数就可以开启web服务器。 // http包中的一个简单的函数就可以开启web服务器。
func learnWebProgramming() { func learnWebProgramming() {
// ListenAndServe第一个参数指定了监听端口第二个参数是一个接口特定是http.Handler。 // ListenAndServe第一个参数指定了监听端口第二个参数是一个接口特定是http.Handler。
err := http.ListenAndServe(":8080", pair{}) err := http.ListenAndServe(":8080", pair{})
fmt.Println(err) // 不要无视错误。 fmt.Println(err) // 不要无视错误。
} }
// 使pair实现http.Handler接口的ServeHTTP方法。 // 使pair实现http.Handler接口的ServeHTTP方法。
func (p pair) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (p pair) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// 使用http.ResponseWriter返回数据 // 使用http.ResponseWriter返回数据
w.Write([]byte("You learned Go in Y minutes!")) w.Write([]byte("You learned Go in Y minutes!"))
} }
``` ```