C语言数组和字符串笔记

C语言数组和字符串笔记

1. 数组及其相关概念

1.1 为什么需要使用数组?

数组是一个有序的、类型相同的数据集合。这些数据被称为数组的元素。每个数组都有一个名字,数组名代表数组的起始地址。数组的元素通过索引或下标访问,索引从0开始。

1.2 数组的定义

在使用数组之前,必须先定义数组。数组的定义包括以下几个部分:

  • 存储类型 (如 int, char 等)
  • 数据类型(数组元素的类型)
  • 数组名(数组的标识符)
  • 数组大小(数组元素的个数)
数组定义语法:
c 复制代码
存储类型 数据类型 数组名[数组长度];

例如:

c 复制代码
int player[11];
数组的规范:
  • 数组的元素必须具有相同的数据类型。
  • 数组的元素可以通过下标访问,下标是从0开始的。
  • 数组的下标可以使用整型表达式,如 array[3+2]

2. 数组的存储方式

2.1 一维数组的存放方式

在内存中,一维数组的元素是连续存放的,每个元素占用的字节数与数据类型的字节数相同。

例如,定义一个浮点型数组 float mark[100];,每个元素占用4个字节。数组的存储形式如下:

c 复制代码
text 低地址         高地址
mark[0]  mark[1]  mark[2] ... mark[99]

2.2 数组初始化

  • 数组初始化是在定义时给数组的元素赋初值。
  • 可以给部分元素赋值,未赋值的元素将自动初始化为0。
初始化语法:
c 复制代码
类型 数组名[常量表达式] = {值1, 值2, ..., 值n};
示例:
c 复制代码
int ary[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

2.3 初始化的规则

  • 如果初始化数据个数少于数组长度,未初始化的元素会被自动赋值为0。
  • 如果初始化数据个数多于数组长度,编译器会报错。
  • 数组长度可以隐式指定。
示例:
c 复制代码
int ary1[] = {1, 2, 3, 4, 5};  // 数组长度自动为5

3. 二维数组

3.1 二维数组的定义

二维数组可以看作是由多个一维数组组成的数组,通常表示一个矩阵或表格。二维数组的声明如下:

c 复制代码
数据类型 数组名[行数][列数];
示例:
c 复制代码
int temp[4][3];  // 定义一个 4 行 3 列的二维数组

3.2 二维数组初始化

可以使用不同的方式初始化二维数组:

示例:
c 复制代码
int a[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};

3.3 二维数组的访问

二维数组的元素可以通过行和列的下标访问。例如,访问 a[1][2] 就是访问二维数组中第二行第三列的元素。

3.4 矩阵转置示例

c 复制代码
#include <stdio.h>
#define MAX_ROW 2
#define MAX_COL 3

void main() {
    int a[MAX_ROW][MAX_COL] = {{1, 2, 3}, {4, 5, 6}};
    int b[MAX_COL][MAX_ROW];
    
    // 矩阵转置
    for (int i = 0; i < MAX_ROW; i++) {
        for (int j = 0; j < MAX_COL; j++) {
            b[j][i] = a[i][j];
        }
    }
    
    // 输出转置后的矩阵
    for (int i = 0; i < MAX_COL; i++) {
        for (int j = 0; j < MAX_ROW; j++) {
            printf("%4d", b[i][j]);
        }
        putchar('\n');
    }
}

4. 字符数组和字符串

4.1 字符串常量

字符串常量是由双引号括起来的字符序列。例如,字符串 "hello" 在内存中的存储方式如下:

c 复制代码
h e l l o \0

其中,'\0' 是字符串的结束符。

4.2 字符数组与字符串

C语言没有专门的字符串类型,字符串是通过字符数组来实现的。字符数组用于存储一个字符串,二维字符数组用于存储多个字符串。

字符串数组定义示例:
c 复制代码
char str[10];  // 声明一个字符数组,最多存储9个字符+结束符

4.3 字符串的初始化

  • 字符串初始化时,C语言会自动在字符串末尾添加一个 '\0' 作为结束符。
示例:
c 复制代码
char str[6] = "hello";  // 自动在末尾加上 '\0'

4.4 字符串的使用

字符数组也可以像普通数组一样使用,通过下标访问和修改字符数组的元素。

c 复制代码
char str[6] = "hello";
str[0] = 'H';  // 修改字符串的第一个字符

5. 字符串输入输出操作

5.1 输入字符串

使用 scanf 函数来输入字符串,使用 %s 格式说明符:

c 复制代码
char str[100];
scanf("%s", str);  // 输入字符串

5.2 输出字符串

使用 printf 函数输出字符串,使用 %s 格式说明符:

c 复制代码
printf("%s", str);  // 输出字符串

5.3 getsputs 函数

  • gets:用于从标准输入获取字符串,直到遇到换行符。
  • puts:用于输出字符串,并自动换行。

5.4 sprintf 函数

sprintf 将格式化的字符串输出到字符数组中。常用于将数值转换为字符串。

c 复制代码
char buffer[100];
int num = 10;
sprintf(buffer, "Number is: %d", num);  // 将整数格式化为字符串

6. 字符串处理函数

6.1 strlen 函数

用于计算字符串的长度,不包括字符串的结束符 '\0'

c 复制代码
int len = strlen(str);

6.2 strcpy 函数

将一个字符串复制到另一个字符串。

c 复制代码
strcpy(dest, source);

6.3 strcat 函数

将两个字符串连接起来。

c 复制代码
strcat(dest, source);

6.4 strcmp 函数

比较两个字符串,返回值说明:

  • 返回值小于0:str1 < str2
  • 返回值等于0:str1 == str2
  • 返回值大于0:str1 > str2
c 复制代码
int result = strcmp(str1, str2);

6.5 strchrstrstr 函数

  • strchr:查找一个字符在字符串中第一次出现的位置。
  • strstr:查找一个子字符串在另一个字符串中的位置。
c 复制代码
 char *ptr = strchr(str, 'a');  // 查找字符 'a'
char *ptr = strstr(str, "abc");  // 查找子字符串 "abc"

7. C语言中的字符函数

7.1 头文件 ctype.h

  • isalnum:检查是否为字母或数字。
  • isalpha:检查是否为字母。
  • isdigit:检查是否为数字。
  • islower:检查是否为小写字母。
  • isupper:检查是否为大写字母。
  • isspace:检查是否为空白字符。

8. 类型转换函数

8.1 头文件 stdlib.h

  • atof:将字符串转换为浮点型。
  • atoi:将字符串转换为整型。
  • atol:将字符串转换为长整型。
c 复制代码
double num = atof("3.14");
int x = atoi("123");
long y = atol("123456");

9. C语言数组案例

第一个案例是经典冒泡排序,第二个 =="小"==案例是简易五子棋,但是用各种符号设置棋盘,下棋时,棋盘总是会发生改动,我尝试修改多次,都无法解决这个问题,最终替换掉了所有的符号,只用" . " 来显示,打印棋盘时加入判断,每落一次棋子,其实相当于打印了一次棋盘,将原有的" . "替换为白子或者黑子。可以完美解决棋盘动的问题,当然,也尝试加入边框,但是这个时候就不是下在交叉线上了,而是框里。本来想着随机落子就行,后来想弄高级一点,就查了查资料,用了Alpha-Beta算法来优化计算机落子。(反正用鸡皮提改了又改,最后反正能跑了)。拒不承认输了一次。

修改前:

解决后:

9.1 五子棋源码

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

#define SIZE 15  // 棋盘大小
#define DEPTH 4  // 搜索深度
#define EMPTY 0
#define BLACK 1
#define WHITE 2

// 函数声明
void printBoard();
int isValidPos(int x, int y);
int evaluatePosition(int x, int y, int player);
void findBestMove(int player, int *bestX, int *bestY);
void playerMove(int player);
void aiMove(int player);
int checkWin(int x, int y, int player);
int checkDraw();
void playGomoku();

int lastMoveX = -1, lastMoveY = -1;  // 全局变量,用于记录最后落子位置


// 方向数组
const int dx[] = {1, 0, 1, 1};
const int dy[] = {0, 1, 1, -1};

// 棋盘状态
int board[SIZE][SIZE] = {0};

int main() 
{
	int choice;
    
    while(1) 
	{
        printf("\n==== 主菜单 ====\n");
        printf("1. 数组排序\n");
        printf("2. 五子棋游戏\n");
        printf("0. 退出程序\n");
        printf("请输入选择: ");
        
        scanf("%d",&choice);
        
        switch(choice) {
            case 1:
                bubbleSort();
                break;
            case 2:
            	playGomoku();
            	break;
            case 0:
                printf("程序已退出\n");
                return 0;
            default:
                printf("无效选择,请重试\n");
        }
    }
	
	return 0;
}

void bubbleSort()
{
	int arr[5];
	int count = 0;
	int temp;
	int i;
	int j;
	char ch;  // 用于清理缓冲区
	
	printf("请输入5个整数:\n");
	for(i = 0;i < 5;i++)
	{
		printf("请输入第%d个数: ", i + 1); 
		if(scanf("%d", &arr[i]) == 1)
		{
			count++;
		}else
		{
			printf("输入有误!程序结束!\n");
		    while((ch = getchar()) != '\n');
			return;
		}
	}
	
	for(i = 0; i < 5; i++)
	{
		for(j = 0; j < 4 - i; j++)
		{
			if(arr[j] > arr[j+1])
			{
				temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;				
			}
		}
	}
	printf("\n从小到大排序后的结果:\n");
	for(j = 0;j < 5; j++)
	{
		printf("%d ", arr[j]);
	}	
	
}

// 打印棋盘
void printBoard() {
    int i, j;
    
    // 打印多个换行来分隔
    printf("\n\n");
    
    // 打印列标号,确保与点位对齐
    printf("     ");  // 缩进5个空格,与行号对齐
    for(i = 1; i <= SIZE; i++) {
        printf("%2d  ", i);  // 统一使用2字符宽度,后加2空格
    }
    printf("\n\n");

    // 打印主棋盘
    for(i = 0; i < SIZE; i++) {
        // 打印行号,保持对齐
        printf("%2d   ", i + 1);  // 统一使用2字符宽度,后加3空格
            
        // 打印每一行的内容
        for(j = 0; j < SIZE; j++) {
            if(board[i][j] == BLACK)
                printf("●  ");    // 黑子后加2个空格
            else if(board[i][j] == WHITE)
                printf("○  ");    // 白子后加2个空格
            else
                printf("·  ");    // 空位点后加2个空格
        }
        printf("\n\n");  // 每行后打印一个空行
    }
    
    printf("\n请输入落子位置 (行 列): ");
}


// 检查位置是否有效
int isValidPos(int x, int y) {
    return x >= 0 && x < SIZE && y >= 0 && y < SIZE;
}

// 简化的位置评估函数
int evaluatePosition(int x, int y, int player) {
    int score = 0;
    int opponent = 3 - player;
    int d, count, empty, block;
    int nx, ny;
    
    // 检查四个方向
    for(d = 0; d < 4; d++) {
        count = 1;
        empty = 0;
        block = 0;
        
        // 正向检查
        nx = x + dx[d];
        ny = y + dy[d];
        while(isValidPos(nx, ny)) {
            if(board[nx][ny] == player) count++;
            else if(board[nx][ny] == EMPTY) {
                empty++;
                break;
            }
            else {
                block++;
                break;
            }
            nx += dx[d];
            ny += dy[d];
        }
        
        // 反向检查
        nx = x - dx[d];
        ny = y - dy[d];
        while(isValidPos(nx, ny)) {
            if(board[nx][ny] == player) count++;
            else if(board[nx][ny] == EMPTY) {
                empty++;
                break;
            }
            else {
                block++;
                break;
            }
            nx -= dx[d];
            ny -= dy[d];
        }
        
        // 评分规则
        if(count >= 5) score += 100000;
        else if(count == 4) {
            if(empty == 2) score += 10000;  // 活四
            else if(empty == 1) score += 1000;  // 冲四
        }
        else if(count == 3) {
            if(empty == 2) score += 1000;  // 活三
            else if(empty == 1) score += 100;  // 眠三
        }
    }
    return score;
}

// 找出最佳落子位置
void findBestMove(int player, int *bestX, int *bestY) {
    int maxScore = -1;
    int i, j, di, dj, ni, nj;
    int hasNeighbor;
    int score;
    *bestX = SIZE/2;
    *bestY = SIZE/2;
    
    // 只考虑已有棋子周围的空位
    for(i = 0; i < SIZE; i++) {
        for(j = 0; j < SIZE; j++) {
            if(board[i][j] != EMPTY) continue;
            
            // 检查是否有相邻的棋子
            hasNeighbor = 0;
            for(di = -1; di <= 1; di++) {
                for(dj = -1; dj <= 1; dj++) {
                    if(di == 0 && dj == 0) continue;
                    ni = i + di;
                    nj = j + dj;
                    if(isValidPos(ni, nj) && board[ni][nj] != EMPTY) {
                        hasNeighbor = 1;
                        break;
                    }
                }
                if(hasNeighbor) break;
            }
            
            if(!hasNeighbor) continue;
            
            score = evaluatePosition(i, j, player);
            // 考虑防守对手
            score += evaluatePosition(i, j, 3-player) * 0.8;
            
            if(score > maxScore) {
                maxScore = score;
                *bestX = i;
                *bestY = j;
            }
        }
    }
}



// 检查平局
int checkDraw() {
    int i, j;
    for(i = 0; i < SIZE; i++) {
        for(j = 0; j < SIZE; j++) {
            if(board[i][j] == EMPTY) return 0;
        }
    }
    return 1;
}

// 玩家落子
void playerMove(int player) {
    int x, y;
    while(1) {
        printf("请输入落子位置 (行 列): ");
        scanf("%d %d", &x, &y);
        x--; y--;  // 转换为数组索引
        if(isValidPos(x, y) && board[x][y] == EMPTY) {
            board[x][y] = player;
            lastMoveX = x;    // 记录最后落子位置
            lastMoveY = y;
            break;
        }
        printf("无效位置,请重试!\n");
    }
}

// 电脑落子
void aiMove(int player) {
    printf("电脑正在思考...\n");
    int bestX, bestY;
    findBestMove(player, &bestX, &bestY);
    board[bestX][bestY] = player;
    lastMoveX = bestX;    // 记录最后落子位置
    lastMoveY = bestY;
    printf("电脑落子位置:%d %d\n", bestX + 1, bestY + 1);
}

// 检查获胜
int checkWin(int x, int y, int player) {
    if(x < 0 || y < 0) return 0;  // 添加边界检查
    
    int d, count;
    int nx, ny;
    for(d = 0; d < 4; d++) {
        count = 1;
        
        // 正向检查
        nx = x + dx[d];
        ny = y + dy[d];
        while(isValidPos(nx, ny) && board[nx][ny] == player) {
            count++;
            nx += dx[d];
            ny += dy[d];
        }
        
        // 反向检查
        nx = x - dx[d];
        ny = y - dy[d];
        while(isValidPos(nx, ny) && board[nx][ny] == player) {
            count++;
            nx -= dx[d];
            ny -= dy[d];
        }
        
        if(count >= 5) return 1;
    }
    return 0;
}

// 游戏主循环
void playGomoku() {
    int currentPlayer = BLACK;
    int gameOver = 0;
    int i, j;
    
    // 重置最后落子位置
    lastMoveX = -1;
    lastMoveY = -1;
    
    // 初始化棋盘
    for(i = 0; i < SIZE; i++) {
        for(j = 0; j < SIZE; j++) {
            board[i][j] = EMPTY;
        }
    }
    
    printf("\n=== 五子棋游戏 ===\n");
    printf("您执黑子(●),电脑执白子(○)\n");
    printf("请输入落子位置的行号和列号(1-%d)\n\n", SIZE);
    
    while(!gameOver) {
        printBoard();
        
        if(currentPlayer == BLACK) {
            playerMove(currentPlayer);
        } else {
            aiMove(currentPlayer);
        }
        
        // 立即检查胜负
        if(checkWin(lastMoveX, lastMoveY, currentPlayer)) {
            printBoard();
            printf("\n%s胜利!\n", currentPlayer == BLACK ? "玩家" : "电脑");
            gameOver = 1;
            continue;  // 直接结束游戏
        }
        
        if(checkDraw()) {
            printBoard();
            printf("\n游戏平局!\n");
            gameOver = 1;
            continue;
        }
        
        currentPlayer = 3 - currentPlayer;  // 切换玩家
    }
    
    // 游戏结束后等待用户确认
    printf("\n按Enter键返回主菜单...");
    getchar();
    getchar();
相关推荐
LuckyLay15 分钟前
Golang学习笔记_28——工厂方法模式
笔记·学习·设计模式·golang·工厂方法模式
今夜有雨.33 分钟前
线程同步与Mutex
c语言·c++·经验分享·笔记·后端·架构·学习方法
go_bai2 小时前
数据结构——队列
数据结构·经验分享·笔记·学习方法
东京老树根2 小时前
Excel 技巧11 - 如何使用Excel作成简单的排班表(★★),weekday 函数,TEXT函数
笔记·学习·excel
热爱学习地派大星3 小时前
Cadence笔记--原理图导入PCB
笔记·cadence
摸鱼仙人~3 小时前
CBAM-2018学习笔记
pytorch·笔记·学习
敲上瘾5 小时前
深入理解Linux系统内存中文件结构以及缓冲区,模拟实现c语言库文件接口
linux·服务器·c语言·c++·系统架构
扶我起来我还能再做一题6 小时前
循环队列(C语言)
c语言·开发语言
_周游6 小时前
【C语言】_内存拷贝函数memcpy与memmove
c语言·开发语言
Spiffo_Sir7 小时前
【Spiffo】环境配置:Linux下LVGL项目构建(含v8、v9)、针对git不到子项目的手动组装
linux·c语言