6-1 数组基础
C语言设计哲学
include/io_utils.h
#ifndef BASICC_IO_UTILS_IO_UTILS_H_
#define BASICC_IO_UTILS_IO_UTILS_H_
#include <stdio.h>
#include <limits.h>
void PrintBinary(unsigned int value);
//#define PRINT_METADATA
#ifdef PRINT_METADATA
# define PRINTLNF(format, ...) printf("("__FILE__":%d) %s: "format"\n", __LINE__, __FUNCTION__ , ##__VA_ARGS__)
#else
# define PRINTLNF(format, ...) printf(format"\n", ##__VA_ARGS__)
#endif
#define PRINT_CHAR(char_value) PRINTLNF(#char_value": %c", char_value)
#define PRINT_WCHAR(char_value) PRINTLNF(#char_value": %lc", char_value)
#define PRINT_INT(int_value) PRINTLNF(#int_value": %d", int_value)
#define PRINT_LONG(long_value) PRINTLNF(#long_value": %ld", long_value)
#define PRINT_LLONG(long_value) PRINTLNF(#long_value": %lld", long_value)
#define PRINT_BINARY(int_value) PrintBinary((unsigned int) int_value);
#define PRINT_HEX(int_value) PRINTLNF(#int_value": %#x", int_value)
#define PRINT_BOOL(bool_value) PRINTLNF(#bool_value": %s", bool_value ? "true" : "false")
#define PRINT_DOUBLE(double_value) PRINTLNF(#double_value": %g", double_value)
#define PRINT_STRING(string_value) PRINTLNF(#string_value": %s", string_value)
#define PRINT_ARRAY(format, array, length) \
{ int array_index; \
for (array_index = 0; array_index < length; ++array_index) { \
printf(format, array[array_index]); \
};\
printf("\n"); }
#define PRINT_INT_ARRAY_LN(array, length) \
{ int i; \
for (i = 0; i < length; ++i) { \
PRINTLNF(#array"[%d]: %d", i, array[i]); \
}}
#define PRINT_INT_ARRAY(array, length) PRINT_ARRAY("%d, ", array, length)
#define PRINT_CHAR_ARRAY(array, length) PRINT_ARRAY("%c, ", array, length)
#define PRINT_DOUBLE_ARRAY(array, length) PRINT_ARRAY("%g, ", array, length)
#endif //BASICC_IO_UTILS_IO_UTILS_H_
01.array_basics.c
#include <stdio.h>
#include "io_utils.h"
#define ARRAY_SIZE 10
// 全局作用域
int global_array[ARRAY_SIZE];
int main() {
// index from 0!!!
auto int array[ARRAY_SIZE];
for (int i = 0; i < ARRAY_SIZE; ++i) {
//array[i] = i;
PRINT_HEX(global_array[i]);
}
int array_2[ARRAY_SIZE] = {0,1,2,3,4,5,6,7,8,9};
for (int i = 0; i < ARRAY_SIZE; ++i) {
PRINT_INT(array_2[i]);
}
double array_double[5] = {0.1, 2.3};
for (int i = 0; i < 5; ++i) {
PRINT_DOUBLE(array_double[i]);
}
// C99 指定位置初始化
char array_char[5] = {[2] = 'o', 'l', 'l'};
for (int i = 0; i < 5; ++i) {
PRINT_CHAR(array_char[i]);
}
return 0;
}
6-2 数组的边界
02.array_limits
#include <stdio.h>
#include "io_utils.h"
#define ARRAY_SIZE 5
int main() {
int array[ARRAY_SIZE];
int array_with_expression[3 + 2];
PRINT_INT(array[0]);
PRINT_INT(array[5]);
int value = 2;
// ....
// C99, VLA; gcc OK; MSVC ERROR
int array_size_of_value[value];
const int kSize = 5; // C++ OK
int array_size_of_const[kSize]; // C99, VLA; gcc OK; MSVC ERROR
// array[5] => array + 5
return 0;
}
变长数组(VLA)
数组的长度可以用变量来声明的数组
C语言 标准从C99开始支持该特性
GCC 提供了相应的扩展;MSVC不支持
6-3 字符串
#include <stdio.h>
#include "io_utils.h"
int main() {
char string[] = "Hello World";
for (int i = 0; i < 11; ++i) {
PRINT_CHAR(string[i]);
}
// short %hd
// NULL \0
PRINTLNF("%s", string);
char string_zh[] = "你好,中国";
wchar_t ws[] = L"你好,中国";
return 0;
}
6-4 函数的数组类型参数
C语言极致效率之源
04.array_parameter.c
#include <stdio.h>
#include "io_utils.h"
#define LENGTH 10
int SumIntArray(int array[], int length) {
int sum = 0;
for (int i = 0; i < length; ++i) {
sum += array[i];
}
return sum;
}
int main() {
int array[LENGTH] = {1, 4, 7, 0, 10, 33, 654, 392, 23, 43};
PRINT_INT(SumIntArray(array, 10));
int smaller_array[5] = {1,2,3,4,5};
PRINT_INT(SumIntArray(smaller_array, 5));
int bigger_array[15] = {3, 6, 4, 7, 0, 10, 33, 654,6, 4, 7, 0, 10, 33, 654};
PRINT_INT(SumIntArray(bigger_array, 15));
return 0;
}
6-5 二维数组
数组参数的正确使用姿势
05.2d_array.c
#include <stdio.h>
#include "io_utils.h"
// vla C99; gcc; msvc x
void SumIntArrays(int rows, int columns, int array[][columns], int result[]) {
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < columns; ++j) {
result[i] += array[i][j];
}
}
}
int main() {
int vehicle_limits[5][2] = {
0, 5, 1, [1][1] = 6, 2, 7, 3, 8, 4, 9
};
//int [2]
//vehicle_limits[0]
for (int i = 0; i < 5; ++i) {
for (int j = 0; j < 2; ++j) {
vehicle_limits[i][j] = i + j;
}
}
int scores[5][4] = {
{135, 135, 138, 277},
{105, 134, 108, 265},
{113, 107, 145, 232},
{123, 99, 140, 227},
{98, 118, 127, 242}
};
int result[5] = {0};
SumIntArrays(5, 4, scores, result);
PRINT_INT_ARRAY(result, 5);
return 0;
}
6-6 案例:打乱数组的顺序
06.shuffle_array.c
#include <stdio.h>
#include "io_utils.h"
#include <stdlib.h>
#include <time.h>
#define PLAYER_COUNT 50
void SwapElements(int array[], int first, int second) {
int temp = array[first];
array[first] = array[second];
array[second] = temp;
}
void ShuffleArray(int array[], int length) {
srand(time(NULL));
//[0, RAND_MAX]
for (int i = length - 1; i > 0; --i) {
int random_number = rand() % i;
SwapElements(array, i, random_number);
}
}
int main() {
int players[PLAYER_COUNT];
for (int i = 0; i < 50; ++i) {
players[i] = i;
}
// players : 0, 1, ..., 49
PRINT_INT_ARRAY(players, PLAYER_COUNT);
ShuffleArray(players, PLAYER_COUNT);
PRINT_INT_ARRAY(players, PLAYER_COUNT);
return 0;
}
6-7 案例:数组元素的排序
Lomuto分割法
07.quick_sort.c
#include <stdio.h>
#include "io_utils.h"
#include <stdlib.h>
#include <time.h>
#define PLAYER_COUNT 50
void SwapElements(int array[], int first, int second) {
int temp = array[first];
array[first] = array[second];
array[second] = temp;
}
void ShuffleArray(int array[], int length) {
srand(time(NULL));
//[0, RAND_MAX]
for (int i = length - 1; i > 0; --i) {
int random_number = rand() % i;
SwapElements(array, i, random_number);
}
}
int Partition(int array[], int low, int high) {
int pivot = array[high];
int partition = low;
for (int i = low; i < high; ++i) {
if (array[i] < pivot) {
SwapElements(array, i, partition++);
}
}
SwapElements(array, partition, high);
return partition;
}
void QuickSort(int array[], int low, int high) {
if (low >= high) return;
int partition = Partition(array, low, high);
QuickSort(array, low, partition - 1);
QuickSort(array, partition + 1, high);
}
int main() {
int players[PLAYER_COUNT];
for (int i = 0; i < 50; ++i) {
players[i] = i;
}
// players : 0, 1, ..., 49
PRINT_INT_ARRAY(players, PLAYER_COUNT);
ShuffleArray(players, PLAYER_COUNT);
PRINT_INT_ARRAY(players, PLAYER_COUNT);
QuickSort(players, 0, PLAYER_COUNT - 1);
PRINT_INT_ARRAY(players, PLAYER_COUNT);
return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.17)
get_filename_component(ProjectId ${CMAKE_CURRENT_SOURCE_DIR} NAME)
string(REPLACE " " "_" ProjectId ${ProjectId})
project(${ProjectId} C)
set(CMAKE_C_STANDARD 11)
include_directories("include")
file(GLOB files "${CMAKE_CURRENT_SOURCE_DIR}/*.c")
foreach(file ${files})
get_filename_component(name ${file} NAME)
add_executable(${name} ${file})
endforeach()