mirror of
https://github.com/adambard/learnxinyminutes-docs.git
synced 2025-04-27 07:33:57 +00:00
Merge 0c5eb762c4
into 8e94abc88b
This commit is contained in:
commit
19ff753258
155
c.html.markdown
155
c.html.markdown
@ -11,6 +11,7 @@ contributors:
|
|||||||
- ["Joshua Li", "https://github.com/JoshuaRLi"]
|
- ["Joshua Li", "https://github.com/JoshuaRLi"]
|
||||||
- ["Dragos B. Chirila", "https://github.com/dchirila"]
|
- ["Dragos B. Chirila", "https://github.com/dchirila"]
|
||||||
- ["Heitor P. de Bittencourt", "https://github.com/heitorPB/"]
|
- ["Heitor P. de Bittencourt", "https://github.com/heitorPB/"]
|
||||||
|
- ["Chris Harding", "https://github.com/sjrct"]
|
||||||
---
|
---
|
||||||
|
|
||||||
Ah, C. Still **the** language of modern high-performance computing.
|
Ah, C. Still **the** language of modern high-performance computing.
|
||||||
@ -27,7 +28,8 @@ memory management and C will take you as far as you need to go.
|
|||||||
>
|
>
|
||||||
> `-Wall -Wextra -Werror -O2 -std=c99 -pedantic`
|
> `-Wall -Wextra -Werror -O2 -std=c99 -pedantic`
|
||||||
>
|
>
|
||||||
> For information on what these flags do as well as other flags, consult the man page for your C compiler (e.g. `man 1 gcc`) or just search online.
|
> For information on what these flags do as well as other flags, consult the man
|
||||||
|
> page for your C compiler (e.g. `man 1 gcc`) or just search online.
|
||||||
|
|
||||||
```c
|
```c
|
||||||
// Single-line comments start with // - only available in C99 and later.
|
// Single-line comments start with // - only available in C99 and later.
|
||||||
@ -68,21 +70,23 @@ enum days {SUN = 1, MON, TUE, WED = 99, THU, FRI, SAT};
|
|||||||
|
|
||||||
// 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(void);
|
||||||
int function_2(void);
|
int function_2(int a, float b);
|
||||||
|
|
||||||
// At a minimum, you must declare a 'function prototype' before its use in any function.
|
// At a minimum, you must declare a 'function prototype' before its use in any
|
||||||
// Normally, prototypes are placed at the top of a file before any function definition.
|
// 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
|
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),
|
// although `int add_two_ints(int, int);` is also valid (no need to name the
|
||||||
// it is recommended to name arguments in the prototype as well for easier inspection
|
// args), it is recommended to name arguments in the prototype as well for
|
||||||
|
// easier inspection
|
||||||
|
|
||||||
// Function prototypes are not necessary if the function definition comes before
|
// Function prototypes are not necessary if the function definition comes before
|
||||||
// any other function that calls that function. However, it's standard practice to
|
// any other function that calls that function. However, it's standard practice
|
||||||
// always add the function prototype to a header file (*.h) and then #include that
|
// to always add the function prototype to a header file (*.h) and then #include
|
||||||
// file at the top. This prevents any issues where a function might be called
|
// that file at the top. This prevents any issues where a function might be
|
||||||
// before the compiler knows of its existence, while also giving the developer a
|
// called before the compiler knows of its existence, while also giving the
|
||||||
// clean header file to share with the rest of the project.
|
// 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
|
// 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
|
// be anything, however most operating systems expect a return type of `int` for
|
||||||
@ -125,7 +129,8 @@ int main (int argc, char** argv)
|
|||||||
short x_short = 0;
|
short x_short = 0;
|
||||||
|
|
||||||
// chars are defined as the smallest addressable unit for a processor.
|
// 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).
|
// 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 x_char = 0;
|
||||||
char y_char = 'y'; // Char literals are quoted with ''
|
char y_char = 'y'; // Char literals are quoted with ''
|
||||||
|
|
||||||
@ -153,8 +158,8 @@ int main (int argc, char** argv)
|
|||||||
// sizeof(obj) yields the size of the expression (variable, literal, etc.).
|
// sizeof(obj) yields the size of the expression (variable, literal, etc.).
|
||||||
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)
|
||||||
|
|
||||||
// If the argument of the `sizeof` operator is an expression, then its argument
|
// If the argument of the `sizeof` operator is an expression, then its
|
||||||
// is not evaluated (except VLAs (see below)).
|
// argument is not evaluated (except VLAs (see below)).
|
||||||
// The value it yields in this case is a compile-time constant.
|
// The value it yields in this case is a compile-time constant.
|
||||||
int a = 1;
|
int a = 1;
|
||||||
// size_t is an unsigned integer type of at least 2 bytes used to represent
|
// size_t is an unsigned integer type of at least 2 bytes used to represent
|
||||||
@ -171,15 +176,15 @@ int main (int argc, char** argv)
|
|||||||
// You can initialize an array of twenty ints that all equal 0 thusly:
|
// You can initialize an array of twenty ints that all equal 0 thusly:
|
||||||
int my_array[20] = {0};
|
int my_array[20] = {0};
|
||||||
// where the "{0}" part is called an "array initializer".
|
// where the "{0}" part is called an "array initializer".
|
||||||
// All elements (if any) past the ones in the initializer are initialized to 0:
|
// Elements (if any) past the ones in the initializer are initialized to 0:
|
||||||
int my_array[5] = {1, 2};
|
int my_array[5] = {1, 2};
|
||||||
// So my_array now has five elements, all but the first two of which are 0:
|
// So my_array now has five elements, all but the first two of which are 0:
|
||||||
// [1, 2, 0, 0, 0]
|
// [1, 2, 0, 0, 0]
|
||||||
// NOTE that you get away without explicitly declaring the size
|
// NOTE that you get away without explicitly declaring the size of the
|
||||||
// of the array IF you initialize the array on the same line:
|
// array IF you initialize the array on the same line:
|
||||||
int my_array[] = {0};
|
int my_array[] = {0};
|
||||||
// NOTE that, when not declaring the size, the size of the array is the number
|
// NOTE that, when not declaring the size, the array's size is the number of
|
||||||
// of elements in the initializer. With "{0}", my_array is now of size one: [0]
|
// 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
|
// To evaluate the size of the array at run-time, divide its byte size by the
|
||||||
// byte size of its element type:
|
// byte size of its element type:
|
||||||
size_t my_array_size = sizeof(my_array) / sizeof(my_array[0]);
|
size_t my_array_size = sizeof(my_array) / sizeof(my_array[0]);
|
||||||
@ -249,7 +254,7 @@ int main (int argc, char** argv)
|
|||||||
i2 * i1; // => 2
|
i2 * i1; // => 2
|
||||||
i1 / i2; // => 0 (0.5, but truncated towards 0)
|
i1 / i2; // => 0 (0.5, but truncated towards 0)
|
||||||
|
|
||||||
// You need to cast at least one integer to float to get a floating-point result
|
// You need to cast at least one int to float to get a floating-point result
|
||||||
(float)i1 / i2; // => 0.5f
|
(float)i1 / i2; // => 0.5f
|
||||||
i1 / (double)i2; // => 0.5 // Same with double
|
i1 / (double)i2; // => 0.5 // Same with double
|
||||||
f1 / f2; // => 0.5, plus or minus epsilon
|
f1 / f2; // => 0.5, plus or minus epsilon
|
||||||
@ -366,13 +371,17 @@ int main (int argc, char** argv)
|
|||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
// *****NOTES*****:
|
// *****NOTES*****:
|
||||||
// Loops and Functions MUST have a body. If no body is needed:
|
// If the body of control expression is only one statement then parentheses
|
||||||
|
// are optional, but recommended:
|
||||||
|
for (jj = 0; jj < 5; jj++)
|
||||||
|
printf("%d\n", jj);
|
||||||
|
|
||||||
|
// Loops and if statements MUST have a body. If no body is needed:
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i <= 5; i++) {
|
for (i = 0; i <= 5; i++) {
|
||||||
; // use semicolon to act as the body (null statement)
|
|
||||||
}
|
}
|
||||||
// Or
|
// Or
|
||||||
for (i = 0; i <= 5; i++);
|
for (i = 0; i <= 5; i++); // semicolon acts as the body (null statement)
|
||||||
|
|
||||||
// branching with multiple choices: switch()
|
// branching with multiple choices: switch()
|
||||||
switch (a) {
|
switch (a) {
|
||||||
@ -441,8 +450,9 @@ int main (int argc, char** argv)
|
|||||||
// without warning.
|
// 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)
|
||||||
|
|
||||||
// For determining the max value of a `char`, a `signed char` and an `unsigned char`,
|
// For determining the max value of a `char`, a `signed char` and an
|
||||||
// respectively, use the CHAR_MAX, SCHAR_MAX and UCHAR_MAX macros from <limits.h>
|
// `unsigned char`, 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", (double) 100); // %f always formats a double...
|
printf("%f\n", (double) 100); // %f always formats a double...
|
||||||
@ -453,9 +463,9 @@ int main (int argc, char** argv)
|
|||||||
// 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
|
||||||
// also tell you the type of data it points to. You can retrieve the memory address
|
// will also tell you the type of data it points to. You can retrieve the
|
||||||
// of your variables, then mess with them.
|
// memory address 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
|
||||||
@ -493,9 +503,9 @@ int main (int argc, char** argv)
|
|||||||
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).
|
||||||
// This works because arrays often decay into pointers to their first element.
|
// This works because arrays often decay into pointers to their first element.
|
||||||
// For example, when an array is passed to a function or is assigned to a pointer,
|
// For example, when an array is passed to a function or is assigned to a
|
||||||
// it decays into (implicitly converted to) a pointer.
|
// pointer, it decays into (implicitly converted to) a pointer.
|
||||||
// Exceptions: when the array is the argument of the `&` (address-of) operator:
|
// Exception: when the array is the argument of the `&` (address-of) operator:
|
||||||
int arr[10];
|
int arr[10];
|
||||||
int (*ptr_to_arr)[10] = &arr; // &arr is NOT of type `int *`!
|
int (*ptr_to_arr)[10] = &arr; // &arr is NOT of type `int *`!
|
||||||
// It's of type "pointer to array" (of ten `int`s).
|
// It's of type "pointer to array" (of ten `int`s).
|
||||||
@ -514,22 +524,23 @@ int main (int argc, char** argv)
|
|||||||
|
|
||||||
// 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,
|
||||||
// may not be true on e.g. embedded systems - the C standard says nothing about it).
|
// although this 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
|
*(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)
|
||||||
|
|
||||||
// Be careful passing user-provided values to malloc! If you want
|
// Be careful passing user-provided values to malloc! If you want to be safe,
|
||||||
// to be safe, you can use calloc instead (which, unlike malloc, also zeros out the memory)
|
// you can use calloc instead (which, unlike malloc, also zeros the memory)
|
||||||
int* my_other_ptr = calloc(20, sizeof(int));
|
int* my_other_ptr = calloc(20, sizeof(int));
|
||||||
|
|
||||||
// Note that there is no standard way to get the length of a
|
// Note that there is no standard way to get the length of a dynamically
|
||||||
// dynamically allocated array in C. Because of this, if your arrays are
|
// allocated array in C. Because of this, if your arrays are going to be
|
||||||
// going to be passed around your program a lot, you need another variable
|
// passed around your program a lot, you need another variable to keep track
|
||||||
// to keep track of the number of elements (size) of an array. See the
|
// of the number of elements (size) of an array. See the functions section
|
||||||
// functions section for more info.
|
// for more info.
|
||||||
size_t size = 10;
|
size_t size = 10;
|
||||||
int *my_arr = calloc(size, sizeof(int));
|
int *my_arr = calloc(size, sizeof(int));
|
||||||
// Add an element to the array
|
// Add an element to the array
|
||||||
@ -541,9 +552,9 @@ int main (int argc, char** argv)
|
|||||||
}
|
}
|
||||||
my_arr[10] = 5;
|
my_arr[10] = 5;
|
||||||
|
|
||||||
// Dereferencing memory that you haven't allocated gives
|
// Dereferencing memory that you haven't allocated gives "unpredictable
|
||||||
// "unpredictable results" - the program is said to invoke "undefined behavior"
|
// 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
|
||||||
@ -552,8 +563,8 @@ int main (int argc, char** argv)
|
|||||||
|
|
||||||
// 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'
|
||||||
|
|
||||||
@ -635,8 +646,8 @@ printf("first: %d\nsecond: %d\n", first, second);
|
|||||||
// Return multiple values.
|
// Return multiple values.
|
||||||
// C does not allow for returning multiple values with the return statement. If
|
// 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
|
// 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
|
// variables where they would like the returned values to go. These variables
|
||||||
// be passed in as pointers such that the function can modify them.
|
// 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)
|
int return_multiple(int *array_of_3, int *ret1, int *ret2, int *ret3)
|
||||||
{
|
{
|
||||||
if (array_of_3 == NULL)
|
if (array_of_3 == NULL)
|
||||||
@ -672,15 +683,15 @@ printIntArray(my_arr, size);
|
|||||||
// will print "arr[0] is: 1" etc
|
// will print "arr[0] is: 1" etc
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// if referring to external variables outside function, you should use the extern keyword.
|
// if referring to external variables outside function, use the extern keyword.
|
||||||
int i = 0;
|
int i = 0;
|
||||||
void testFunc() {
|
void testFunc(void) {
|
||||||
extern int i; //i here is now using external variable i
|
extern int i; //i here is now using external variable i
|
||||||
}
|
}
|
||||||
|
|
||||||
// make external variables private to source file with static:
|
// make external variables private to source file with static:
|
||||||
static int j = 0; //other files using testFunc2() cannot access variable j
|
static int j = 0; //other files using testFunc2() cannot access variable j
|
||||||
void testFunc2() {
|
void testFunc2(void) {
|
||||||
extern int j;
|
extern int j;
|
||||||
}
|
}
|
||||||
// The static keyword makes a variable inaccessible to code outside the
|
// The static keyword makes a variable inaccessible to code outside the
|
||||||
@ -693,6 +704,18 @@ void testFunc2() {
|
|||||||
// declared with some other starting value.
|
// declared with some other starting value.
|
||||||
//**You may also declare functions as static to make them private**
|
//**You may also declare functions as static to make them private**
|
||||||
|
|
||||||
|
// Note that before C23, and unlike C++, functions taking no arguments without
|
||||||
|
// an explicit `void` inside the parameter list will be treated as taking an
|
||||||
|
// unknown number of arguments rather than no arguments.
|
||||||
|
void testFunc3(void) {
|
||||||
|
// Functions can be prototyped inside other functions
|
||||||
|
void foobie();
|
||||||
|
void bletch(void);
|
||||||
|
|
||||||
|
foobie(1, 2, 3); // This will give a warning at most, not an error
|
||||||
|
bletch(1, 2, 3); // This will produce an error
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
// User-defined types and structs
|
// User-defined types and structs
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
@ -713,10 +736,16 @@ struct rectangle {
|
|||||||
// due to potential padding between the structure members (this is for alignment
|
// due to potential padding between the structure members (this is for alignment
|
||||||
// reasons). [1]
|
// reasons). [1]
|
||||||
|
|
||||||
void function_1()
|
void function_1(void)
|
||||||
{
|
{
|
||||||
struct rectangle my_rec = { 1, 2 }; // Fields can be initialized immediately
|
struct rectangle my_rec = { 1, 2 }; // Fields can be initialized immediately
|
||||||
|
|
||||||
|
// Fields can also be initialized in an arbitrary order with the field name
|
||||||
|
struct rectangle my_rec2 = {
|
||||||
|
.height = 2,
|
||||||
|
.width = 1
|
||||||
|
};
|
||||||
|
|
||||||
// Access struct members with .
|
// Access struct members with .
|
||||||
my_rec.width = 10;
|
my_rec.width = 10;
|
||||||
my_rec.height = 20;
|
my_rec.height = 20;
|
||||||
@ -760,10 +789,10 @@ int areaptr(const rect *r)
|
|||||||
// Function pointers
|
// Function pointers
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
/*
|
/*
|
||||||
At run time, functions are located at known memory addresses. Function pointers are
|
At run time, functions are located at known memory addresses. Function pointers
|
||||||
much like any other pointer (they just store a memory address), but can be used
|
are much like any other pointer (they just store a memory address), but can be
|
||||||
to invoke functions directly, and to pass handlers (or callback functions) around.
|
used to invoke functions directly, and to pass handlers (or callback functions)
|
||||||
However, definition syntax may be initially confusing.
|
around. However, definition syntax may be initially confusing.
|
||||||
|
|
||||||
Example: use str_reverse from a pointer
|
Example: use str_reverse from a pointer
|
||||||
*/
|
*/
|
||||||
@ -773,12 +802,13 @@ void str_reverse_through_pointer(char *str_in) {
|
|||||||
f = &str_reverse; // Assign the address for the actual function (determined at run time)
|
f = &str_reverse; // Assign the address for the actual function (determined at run time)
|
||||||
// f = str_reverse; would work as well - functions decay into pointers, similar to arrays
|
// f = str_reverse; would work as well - functions decay into pointers, similar to arrays
|
||||||
(*f)(str_in); // Just calling the function through the pointer
|
(*f)(str_in); // Just calling the function through the pointer
|
||||||
// f(str_in); // That's an alternative but equally valid syntax for calling it.
|
// f(str_in); // That's an alternative but equally valid syntax for calling it
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
As long as function signatures match, you can assign any function to the same pointer.
|
As long as function signatures match, you can assign any function to the same
|
||||||
Function pointers are usually typedef'd for simplicity and readability, as follows:
|
pointer. Function pointers are usually typedef'd for simplicity and readability,
|
||||||
|
as follows:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef void (*my_fnp_type)(char *);
|
typedef void (*my_fnp_type)(char *);
|
||||||
@ -864,8 +894,8 @@ as the C file.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* A safe guard to prevent the header from being defined too many times. This */
|
/* A safe guard to prevent the header from being defined too many times. This */
|
||||||
/* happens in the case of circle dependency, the contents of the header is */
|
/* happens in the case of circlular dependencies, or such as when a header is */
|
||||||
/* already defined. */
|
/* included alongside a header that includes the same header itself. */
|
||||||
#ifndef EXAMPLE_H /* if EXAMPLE_H is not yet defined. */
|
#ifndef EXAMPLE_H /* if EXAMPLE_H is not yet defined. */
|
||||||
#define EXAMPLE_H /* Define the macro EXAMPLE_H. */
|
#define EXAMPLE_H /* Define the macro EXAMPLE_H. */
|
||||||
|
|
||||||
@ -897,7 +927,8 @@ enum traffic_light_state {GREEN, YELLOW, RED};
|
|||||||
|
|
||||||
/* Function prototypes can also be defined here for use in multiple files, */
|
/* Function prototypes can also be defined here for use in multiple files, */
|
||||||
/* but it is bad practice to define the function in the header. Definitions */
|
/* but it is bad practice to define the function in the header. Definitions */
|
||||||
/* should instead be put in a C file. */
|
/* should instead be put in a C file. An uncommon exception is when defining */
|
||||||
|
/* static inline functions. */
|
||||||
Node createLinkedList(int *vals, int len);
|
Node createLinkedList(int *vals, int len);
|
||||||
|
|
||||||
/* Beyond the above elements, other definitions should be left to a C source */
|
/* Beyond the above elements, other definitions should be left to a C source */
|
||||||
|
Loading…
Reference in New Issue
Block a user