plc字符串怎么计算字节数_我的C语言学习笔记(十二)字符串

12.0.0 字符串

12.1.0 二维数组的基本使用

12.1.1 二维数组的声明

二维数组就是一个有行有列的表格。

我们声明一个二维数组,就相当于在内存中创建了指定行指定列的一个表格来存储数据。

二维数组首先是一个数组,所以它符合数组的一般特点:

  • 元素的类型相同
  • 存储的数据的个数固定
  • 方便管理数据

另外它也有自己独特的特点:

  • 二维数组是一个有行有列的表格
  • 使用单元格来存储数据,单元格就是二维数组的元素

声明二维数组的语法:

元素类型 数组名[行数][列数];

例如:

int arr[3][4];

表示在内存中声明了一个二维数组,这个二维数组的名字叫做arr;

这个二维数组表示1个3行4列的表格;

每个单元格就是这个二维数组的一个元素;

每个元素的类型是int类型。

几个术语:

  • 元素:就是这个二维数组表格的每一个单元格。
  • 下标:二维数组的元素的下标有两个,一个是行下标,一个是列下标。
  • 长度:一般把单元格的个数叫做二维数组的长度。行*列

12.1.2 如何往二维数组中存储数据

对于二维数组,在存储数据的时候,必须要确定到底要存储到哪一个元素之中。而下标是用来确定二维数组中的元素的,所以我们可以用下标来表示每一个元素的在二维数组中的位置,进而用来为元素赋值。唯一要注意的是二维数组的下标有两个,行下标和列下标:

二维数组名[行下标][列下标] = 数据;

int arr[3][4];
int arr[1][2] = 100;

表示将100赋值给arr这个二维数组的第1行第2列的元素。

注意:

  • 赋值的数据类型应该和定义的二维数组的类型一致,否则将会自动产生类型转换;
  • 行、列下标不要越界,否则可能会造成程序崩溃。

12.1.3 如何从二维数组中取出数据

还是通过二维数组的下标来取出其元素的数据,唯一要注意的是下标有两个:

二维数组名[行下标][列下标];

注意:行列下标不要越界。

如何遍历二维数组的所有元素?

代码例子:

for (int i = 0; i < 行数; i++)
{
 for (int j = 0; j < 列数; j++)
 {
   printf(“%dt”,arr[i][j]);
 }
}

12.1.4 二维数组的注意事项

关于二维数组的行数和列数:

  • 在声明二维数组的时候,必须要指定行数和列数
  • 行数和列数可以是变量、常量、宏、表达式,也可以是1或0.
  • 行数和列数不能是小数和负数

关于二维数组的元素的默认值:

如果我们声明一个二维数组的时候,没有为其赋值,那么这个二维数组中的元素是有值的,这些值都是垃圾值。

12.1.5 二维数组的初始化

二维数组的全部初始化有下列几种方法:

  • 先声明,再使用下标来初始化
  • 在声明的同时,就初始化数组的每一个元素:
int arr[3][4] = 
{
 {10,20,30,40},
 {50,60,70,80},
 {90,100,110,120}
};

这种方式初始化时可以参略行数

  • 可以参略里面的大括号,编译器会自己根据数据的多少自动判断行数和列数:
int arr[3][4] = {10,20,30,40,50,60,70,80,90,100,110,120};

这种方式也可以参略行数

部分初始化的方法有如下几种:

  • int arr[3][4] = {{10},{20},{30}};

初始化指定行的数据,那么其他的元素就会被自动初始化为0.

10 0 0 0

20 0 0 0

30 0 0 0

  • int arr[3][4] = {10,20,30,40,50};

按照顺序去初始化每一个元素,其他的元素的值就会被自动初始化为0.

10 20 30 40

50 0 0 0

0 0 0 0

  • 如果省略了行数,也会被系统允许,但是实际计算的行数会根据实际输入的数据个数来决定:
int arr[][4] = {10,20,30,40,50};

系统会根据输入的数据个数来计算行数,上面的数据有5个,而列数已知是4列,所以系统会认为这个二维数组是2行4列。

10 20 30 40

50 0 0 0

  • 给指定的行初始化,其他的元素自动初始化为0:
int arr[3][4] = {[1]={10,20,30,40},[2]={50,60,70,80}};

这个时候这个二维数组的内容如下:

0 0 0 0

10 20 30 40

50 60 70 80

  • 给指定的元素赋值,其他的元素自动初始化为0:
int arr[3][4] = {[0][1]=20,[1][3]=60};

这个时候这个二维数组的内容如下:

0 20 0 0

0 0 0 60

0 0 0 0

12.1.6 二维数组的应用场景

某公司,有三个销售小组,每组有4个人

要求用二维数组将其销售成绩存储起来

然后计算:1. 销售之王 2. 求每个小组的平均销售额

代码例子如下:

int arr[3][4] = 
{
 {45,67,34,56},
 {45,23,4,57},
 {21,34,89,77}
};
int max = INT32_MIN;
for (int i = 0;i < 3;i++)
{
 for (int j = 0;j < 4;j++)
 {
   if(arr[i][j] > max)
   {
     max = arr[i][j];
   }
 }
}
printf(“销售之王的销售额是:%d万n”,max);
for (int i = 0;i < 3;i++)
{
 int sum = 0;
 for (int j = 0;j < 4;j++)
 {
   sum += arr[i][j];
 }
 printf(“第%d组的平均销售成绩是:%d万n”,i+1,sum/4);
}

什么时候要使用二维数组?

当有类似于表格形式的数据需要处理的时候,就可以使用二维数组。

12.2.0 二维数组在内存中的形式

12.2.1 二维数组在内存中的存储

一维数组的元素只需要1个下标就可以确定;

二维数组的元素需要2个下标才可以确定。

一维数组像一条线,要确定一条线上的1个点只需要1个下标就可以了;

二维数组像一个面,要确定一个面上的一个点需要两个下标才可以。

那么二维数组是如何在内存中申请空间的呢?

举例:

int arr[2][3];
  • 从高地址向低地址申请了连续的(行*列*每个元素占用的字节数)个字节空间
  • 第0行是在低字节,第0行第0列的元素是在这个数组的内存地址中最低字节。

所以,二维数组在内存中仍然是一块连续的空间,并不是一个表格。

二维数组的本质其实是多个一维数组,在内存中占用了连续的空间。

12.2.2 二维数组的地址和行列计算

组成二维数组的低字节的地址就是这个二维数组的地址,也就是第0行的地址,也就是第0行的第0个元素的地址。

获取二维数组的内存地址可以用如下代码:

printf(“%pn”,arr);
printf(“%pn”,&arr[0][0]);
printf(“%pn”,arr[0]); 

//因为第0行就是一个一维数组,这个数组名就是其地址

所以:

二维数组的地址=二维数组名=二维数组的0行的地址=二维数组的0行0列元素的地址=二维数组低字节的地址

  • 二维数组的长度计算:

二维数组的长度是这个二维数组的所有元素的个数

用二维数组占用的总的字节数 / 每一个元素所占用的字节数

例子:sizeof(arr) / sizeof(arr[0][0]);
  • 二维数组的行数计算:

二维数组的每一行占用的字节数是一样的,所以:

用总的字节数 / 每一行占用的字节数 = 行数

例子:sizeof(arr) / sizeof(arr[0]);
  • 二维数组的列数计算:

每一行的总字节数 / 每一个元素的字节数 = 列数

例子:sizeof(arr[0]) / sizeof(arr[0][0]);

注意:

  • 在声明二维数组的同时使用大括号初始化数组的元素,这个时候行数可以省略,但是列数不可以省略。
  • 在声明二维数组的同时不初始化数组的元素时,行数和列数都不可以省略。

12.3.0 二维数组与函数

12.3.1 使用二维数组作为参数的函数

  • 如果函数的参数时一个一维数组,那么我们在传递参数的时候,可以传递二维数组的某一行,因为二维数组的行其实就是一个一维数组。
  • 二维数组也可以作为函数的参数。

例子:

void test(int arr[3][4])
{
 内代码省略;
}
int arr[3][4] = {10,20,30,40,50,60,70,80,90,100,110,120};
test (arr);
    • 如果函数的参数是一个二维数组,那么在调用的时候,实参也必须是一个同类型的二维数组
    • 当二维数组作为函数的参数的时候,会丢失这个二维数组的行数和列数信息。

因为声明参数二维数组的时候,并不是去创建一个二维数组,而是创建1个用来存储数组地址的指针变量,而指针变量是占据8个字节的。所以这个时候,在函数的内部使用sizeof来计算参数二维数组的占用字节的时候得到的结果永远都是8个字节。

    • 当二维数组作为函数的参数的时候,行数可以省略,但是列数不能省略。并且实参的行数可以任意,但是列数必须和形参的列数保持一致。
    • 解决方法是:让调用者将二维数组的行数和列数都传递到函数内部中来。所以至少还要加上两个参数,一个是行(row),一个是列(column)。

实参二维数组的列数必须要和形参二维数组的列数一致。在写参数的时候,先写行数和列数,最后再写二维数组,然后二维数组的列数用参数指定。

例如:void test(int rows,int cols,int arr[][cols]);

这个时候,传递的二维数组的行数和列数就基本上是任意指定的了,可以在不修改函数的前提下在main函数内随意填写实参二维数组的行数和列数。

案例代码:

从控制台接收用户输入1个二维数组的行数和列数:

  1. 然后创建这个二维数组;
  2. 写一个函数,为这个二维数组的元素赋值:元素的值=(行*列)+
    10;
  3. 再写一个函数,打印二维数组的所有元素。
void setValue(int rows,int cols,int arr[][cols])
{
 for (int i = 0; i < rows; i++);
 {
 for (int j = 0; j < cols; j++);
 {
   arr[i][j] = (i*j)+10;
 }
 }
}

void getValue(int rows,int cols,int arr[][cols])
{
 for (int i = 0; i < rows; i++)
 {
   for (int j = 0; j <cols; j++)
   {
     printf(“%d “,arr[i][j]);
   }
 }
 printf(“n”);
}
int main()
{
 int rows = 0, cols = 0;
 printf(“Please input Rows & Columns:”);
 scanf(“%d%d”,&rows,&cols);
 int arr[rows][cols];
 setValue(rows, cols, arr);
 getValue(rows, cols, arr);
 return 0;
}

12.4.0 字符串

12.4.1 字符数组

  • 声明字符数组

char chs[4];

表示声明了1一个长度为4的字符数组,这个数组的名字叫chs,最多可以存储4个字符。

  • 字符数组的取值和遍历

同样使用for循环来遍历和取值

  • 字符数组的每一个元素本质上就是一个char变量,所以字符数组中的元素仍然不可以存储中文
  • 关于字符数组的默认值问题:

声明一个字符数组,不给这个数组的元素赋值,那么这个字符数组的元素是有值的,值是垃圾值。

在声明字符数组的同时,如果初始化了部分元素,那么其他元素会被初始化为’0’,0的ASCII码为0。

12.4.2 C语言存储字符串数据的方法

之前学习的数据类型有int、double、float、char,但是实际上,还有一种数据是无法存储的,类似于Jack、5354_abc等。

像这样的数据,我们叫做字符串。

在C语言中字符串数据必须要用双引号引起来。

“Jack” “5354_abc”

那如何存储字符串数据呢?

分析一下,Jack其实是由四个字符组成的,所以我们可以用1个字符数组来存储字符串数据,把组成这个字符串数据的每一个字符存储到字符数组中去。

char name[4];
name[0]=‘J’;
name[1]=‘a’;
name[2]=‘c’;
name[3]=‘k’;

所以:

C语言中存储字符串数据的原理是:将字符串数据的每一个字符存储到字符数组中,并在后面追加一个’0’代表字符串存储完毕。

  • 存储字符串的方式:
  1. a.最根本的方式:
char name[5]={‘J’,’a’,’c’,’k’,’0’};

将字符串的每一个字符存储到字符数组中,在后面追见一个’0’代表存储结束

char name[]={‘J’,’a’,’c’,’k’,’0’};
    1. b.简写的方式:
char name[]={“Jack”};

系统自动的会将这个字符串中的每一个字符存储到字符数组中,并自动追加一个’0’

    1. c.最常用的方式:
char name[]=“Jack”;

系统自动的会将这个字符串中的每一个字符存储到字符数组中,并自动追加一个’0’

12.4.3 使用字符数组存储字符串的注意事项

  • 如果使用字符数组存储字符串数据的时候,没有指定长度,那么这个字符数组的长度=字符串的长度+1;
  • 如果指定了字符数组的长度,那么这个字符数组的长度就是指定的长度;
  • 如果指定了字符数组的长度小于等于了字符串的长度,那么这个时候会出现存储不下的情况,系统会报错;
  • 如果在声明一个字符数组的同时就初始化一个字符串给这个数组,这个时候是可以使用中文的;

12.4.4 字符串的输出

虽然可以使用for循环来打印输出字符串,但是这样的操作过于繁琐和没有效率。

C语言系统中可以使用%s的格式控制符来输出存储在字符数组中的字符串数据。

例子:printf(“%sn”,name);

%s的原理:从给定的数组的地址开始1个字节1个字节的输出,直到遇到’0’为止。

12.4.5 如何从控制台接收输入的字符串

使用scanf函数可以实现从控制台接收输入的字符串。

  1. 1.先准备一个字符数组来保存用户输入的字符串数据;
  2. 2.使用scanf函数接收用户输入字符串数据并存储到指定的字符数组中;

例子:

char str[10];
scanf(“%s”,str);

注意:

  • 如果输入的字符串数据长度大于声明的字符数组长度,系统会报错崩溃;
  • 如果在输入字符串的时候,如果输入了空格,系统会认为输入结束,后面的内容会被忽略。

12.4.6 字符串的长度计算

字符串的长度不能使用sizeof来计算的,因为存储字符串的字符数组往往要比字符串长,甚至可能要长出不少。因为有时候数组定义的长度要超出字符串的长度很多。

所以正确的计算方式应该是从这个字符数组的第一个字节开始计数,直到遇到’0’为止。

代码如下:

char name[100] = “Jack”;
int len = 0;
while (name[len] != ‘0’)
{
 len++;
}

12.4.7 与字符串相关的常用函数

  • puts()函数

作用:用来输出字符串

语法格式:puts(字符数组名);

优点:简单,输入完毕会自动换行

缺点:只能输出字符串,也不可以使用占位符

  • gets()函数

作用:从控制台接收用户输入1个字符串数据

语法格式:gets(字符数组名);

优点:当用户输入的字符串数据中有空格时,可以连同空格一起接收

缺点:和scanf函数一样,存在超长度的情况,不安全

————以上两个函数是声明在stdio.h文件中————

————以下四个函数数声明在string.h文件中————

  • strlen()函数

作用:得到存储在字符数组中字符串数据的长度

语法格式:strlen(字符数组名);

注意:在声明变量接收strlen函数的结果时,要使用unsigned long类型。

  • strcmp()函数

作用:用来比较两个字符串的大小

语法格式:strcmp(字符数组名1,字符数组名2);

如果返回的结果是负数,表示字符串1比字符串2小;

如果返回的结果是正数,表示字符串1比字符串2大;

如果返回的结果是0,表示相同。

比较的规则:比的是相同位置的字符的ASCII码的大小

  • strcpy()函数

作用:把存储在1个字符数组中的字符串数据拷贝到另外一个字符数组中存储。

语法格式:strcpy(字符数组名1,字符数组名2);

这个表示将字符数组2的内容拷贝到字符数组1中去。

可能会产生因为两个字符数组长度不一样导致运行崩溃的问题。

  • strcat()函数

作用:把存储在字符数组2的字符串数据2链接到存储字符串1的字符数组1后面

语法格式:strcat(字符数组名1,字符数组名2);

也可能会产生两个字符串因合并后超出字符串的长度定义而运行崩溃的问题。

12.4.8 走出迷宫

代码如下:

#include <stdio.h>
#include <stdlib.h>
#define rows 8
#define cols 8

//用二维数组将地图保存起来
char map[rows][cols] =
{
 {'#','#','#','#','#','#','#','#'},
 {'#','o','#',' ',' ',' ','#','#'},
 {'#',' ','#',' ','#',' ',' ','#'},
 {'#',' ','#',' ',' ','#',' ','#'},
 {'#',' ','#','#',' ','#',' ','#'},
 {'#',' ','#','#',' ','#',' ','#'},
 {'#',' ',' ',' ',' ','#',' ','#'},
 {'#','#','#','#','#','#',' ','#'},
};

//保存小人的初始坐标
int personRow = 1;
int personCol = 1;

/// 打印地图
void showMap(void);

/// 接收用户输入小人方向
char enterDirection(void);

void moveUp(void);

void moveDown(void);

void moveLeft(void);

void moveRight(void);

int main(int argc, const char * argv[])
{
 while (map[7][6] != 'o' )
 {
   system("clear");
   showMap();  
   char dir = enterDirection();  
   switch (dir)
   {
     case 'a':
     case 'A':
       moveLeft();
       break;
     case 'd':
     case 'D':
       moveRight();
       break;
     case 'w':
     case 'W':
       moveUp();
       break;
     case 's':
     case 'S':
       moveDown();
       break;
     case 'q':
     case 'Q':
       printf("已结束游戏!n");
       return 0;
       break;
   }
 }
 printf("恭喜你!已走出迷宫!n");
 return 0;
}

void showMap()
{
 for (int i =0; i < rows; i++)
 {
   for (int j = 0; j < cols; j++)
   {
     printf("%c ",map[i][j]);
   }
   printf("n");
 }
}

char enterDirection()
{
 printf("请输入小人的前进方向:w - 上 s - 下 a - 左 d - 右 q - 结束游戏 n");
 char dir = 'a';
 rewind(stdin);
 scanf("%c",&dir);
 return dir;
}

void moveUp()
{
 int nextRow = personRow - 1;
 int nextCol = personCol;
 if (map[nextRow][nextCol] == ' ')
 {
   map[nextRow][nextCol] = 'o';
   map[personRow][personCol] = ' ';
   personRow = nextRow;
   personCol = nextCol;
 }
}

void moveDown()
{
 int nextRow = personRow + 1; 
 int nextCol = personCol; 
 if (map[nextRow][nextCol] == ' ')
 {
   map[nextRow][nextCol] = 'o';
   map[personRow][personCol] = ' ';
   personRow = nextRow;
   personCol = nextCol;
 }
}

void moveLeft()
{
 int nextRow = personRow;
 int nextCol = personCol - 1;
 if (map[nextRow][nextCol] == ' ')
 {
   map[nextRow][nextCol] = 'o';
   map[personRow][personCol] = ' ';
   personRow = nextRow;
   personCol = nextCol;
 }
}

void moveRight()
{
 int nextRow = personRow;
 int nextCol = personCol + 1;
 if (map[nextRow][nextCol] == ' ')
 {
   map[nextRow][nextCol] = 'o';
   map[personRow][personCol] = ' ';
   personRow = nextRow;
   personCol = nextCol;
 }
}

完整学习笔记会完全记录在我的个人网站和知乎上,免费的pdf和epub版本将来会在我的网站提供下载链接,敬请期待!

此外,本栏目的全部内容已发表在Apple Books Store上,如果有条件的读者(Apple Books在中国大陆地区没有服务)可以点击如下链接购买支持我!谢谢!

Apple Books Store的版本支持目录索引,以及快速查阅,稍后的版本还将支持函数及关键字速查。

Apple Books Store商店链接:

‎简明C语言学习指南​books.apple.com
26580dfc31b7c5652124085346e51cbe.png

我的个人网站:https://beautylife.pub

美丽人生工作室​beautylife.pub

C语言学习笔记的网址:(持续更新)

C语言学习 - BeautyLife Studio​beautylife.pub
2f2df131edf433c2145081bbf19d704b.png

感谢提供我个人网站服务器空间的优网主机:

优网主机 - 安全稳定、简单易用!​my.youwebcloud.com
6906e3266f6c7ef80833020b86cf58cd.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值