mirror of
https://github.com/adambard/learnxinyminutes-docs.git
synced 2024-12-23 09:41:36 +00:00
Edits
This commit is contained in:
parent
5be20756e0
commit
8aa0ab6068
250
c.html.markdown
250
c.html.markdown
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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-подобных языков, разработанный
|
||||||
|
@ -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, предпринимается попытка поиска в папке, где выполняется скрипт
|
||||||
// Если не в одном из этих мест файл не найден - выдается ошибка
|
// или в текущей рабочей директории. Если не в одном из этих мест файл не
|
||||||
|
// найден - выдается ошибка
|
||||||
/* */
|
/* */
|
||||||
|
|
||||||
/********************************
|
/********************************
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
####################################################
|
####################################################
|
||||||
|
@ -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来声明一个slice,make会分配和初始化slice,map和channel。
|
// 用make来声明一个slice,make会分配和初始化slice,map和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!"))
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user