c语言基础学习05_数组和字符串

简介: =============================================================================涉及到的知识点有:for循环有两种写法、数组、一维数组定义与使用、一维数组的初始化、如何得到一个一维数组的成员数量、查找出一维数组中成员最大值、查...

=============================================================================
涉及到的知识点有:for循环有两种写法、数组、一维数组定义与使用、一维数组的初始化、
如何得到一个一维数组的成员数量、查找出一维数组中成员最大值、查找一维数组的第二大元素的值、
一维数组的逆置、一维数组排序:冒泡排序、二维数组、二维数组的初始化、三维数组初始化、三维数组排序、
字符串与字符数组、字符数组的初始化、字符数组的使用(以及字符数组和字符串的区别)、去除输出字符串结尾处的空格、
现在要去掉字符串最右面的空格,而不能去掉字符串中间的空格呢、随机数产生函数rand与srand、
自动的变种子、控制随机数的范围、用scanf来输入字符串、如何把两次输入的字符串放到新的字符串里去、
scanf缓冲区溢出的危险的解释、字符串的逆置。
=============================================================================
for循环有两种写法:

第一种写法:
int i;
for(i = 0; i < 10; i++)      //这个是标准C写法,该写法可以同时兼容c和c++。
{

}

第二种写法:
for(int i = 0; i < 10; i++)   //这个是C++写法,该写法有些编译器不行,不支持。
{

}

区别:两种写法均可以,没有对错!

=============================================================================
数组:就是在内存中连续的相同类型的变量空间。

1、一维数组定义与使用
例如:
int a[10];   //定义了一个一维数组,有10个成员,每个成员都是int类型,在内存中是连续存放的。
int a[10];   //从a[0]开始到a[9]结束,注意:没有a[10]这个元素
a = 5;     //这句话是错误的。
      //数组的名字本身是一个常量,不能作为左值的。即不能把一个数组名当一个变量去用!!!
      //数组名:在c语言中数组名其实就是数组第一个元素的地址,是一个常量。
      (该常量是“变化”的,这里面“变化”的意思是:只要数组大小确定,首元素的地址随之确定)
      //即 a=&a[0]
-----------------------------------------------------------------------------
2、一维数组的初始化
各种各样的写法如下:
char a[5];           //等同于随机初始化,随机赋值
char a[5] = {1,2,3,4};   //等同于定义后就初始化了

//默认后续元素为零的简写
char a[5] = {1,2};       //等同于char a[5] = {1,2,0,0};

//把所有成员的值都设为0的简写
char a[5] = {0};       //等同于char a[5] = {0,0,0,0};

int a[] = {1,2,3};      //等同于int a[3] = {1,2,3}
int a[] = {1,2,3,4,5,6};    //等同于int a[6] = {1,2,3,4,5,6};
-----------------------------------------------------------------------------
3、如何得到一个一维数组的成员数量?

linux下的代码如下:

1 #include <stdio.h>
2
3 int main()
4 {
5    int a[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9,};//定义一个一维数组,每个成员都是int类型,在内存中是连续存放的。
6
7    int i;
8   for (i = 0; i < sizeof(a) / sizeof(a[0]); i++)
9    {
10     printf("a[%d] = %d\n", i, a[i]);
11   }
12    //printf("%lu, %lu\n", sizeof(a), sizeof(a[0]));

13   return 0;
14 }
-----------------------------------------------------------------------------
4、一个一维数组,其成员数量是随机的,数组成员的值也是随机的,需要查找出该数组中成员最大值。

linux下的代码如下:

1 #include <stdio.h>
2
3 int main()
4 {
5   int a[] = {-321, 52, 85, -78, 96, 789};
6      int i;
7   int tmp = a[0];
8   for (i = 1; i < sizeof(a) / sizeof(a[0]); i++)
9   {
10     if (a[i] > tmp)
11      tmp = a[i];
12    }
13   printf("max = %d\n", tmp);

14   return 0;
15 }
-----------------------------------------------------------------------------
5、查找一维数组的第二大元素的值,要求只能用一个循环,也不能用循环嵌套。

linux下的代码如下:

1 #include <stdio.h>
2
3 int main()
4 {
5    int a[] = {-321, 52, 85, -78, 96, 789};
6
7    //默认数组中第一个和第二个成员分别是最大的和第二大的
8    int max = a[0];
9    int smax = a[1];
10     if (a[0] > a[1])
11   {
12     max = a[0];
13     smax = a[1];
14   }
15   else
16  {
17     max = a[1];
18     smax = a[0];
19   }
20
21   int i;
22   for (i = 2; i < sizeof(a) / sizeof(a[0]); i++)
23  {
24      if (a[i] > max)
25      {
26          smax = max;
27        max = a [i];
28      }
29      else if (a[i] < max && a[i] > smax)
30      {
31        smax = a[i];
32      }
33     else
34     {
35     }
36   }
37
38   printf("smax = %d\n", smax);

39   return 0;
40 }
-----------------------------------------------------------------------------
6、一维数组的逆置

vs2017下的代码如下:
#include <stdio.h>

int main()
{
  int a[] = { 45, 87, 56, 89, 52, 456, 489, 1235 };

  int min = 0; //代表数组的最小下标
  int max = 0; //代表数组的最大下标
  max = sizeof(a) / sizeof(a[0]) - 1;

  while (min < max)
  {
    int tmp = a[min];
    a[min] = a[max];
    a[max] = tmp;
    min++;
    max--;
  }
  //两个元素交换的思路:要有一个临时的量,把要交换的某一个量先存起来
  //int tmp = a[0];
  //a[0] = a[7];
  //a[7] = tmp;
  int i;
  for (i = 0; i < sizeof(a) / sizeof(a[0]); i++)
  {
    printf("a[%d] = %d\n", i, a[i]);
  }

  return 0;
}
-----------------------------------------------------------------------------
7、一维数组排序:冒泡排序
名词解释:将一个无序的一维数组排序成一个有序的一维数组,遍历这个一维数组,将最大的成员放到最后一个。
怎么把最大的元素放到最后呢?思路是:两个相邻的元素依次比较,把大的放到小的后面。

例如:冒泡排序思路
第一次循环的时候:
12,45,73,55,81,36
12,45,55,73,81,36
12,45,55,73,36,81   这样最大的元素跑到了最后

第二次再循环的时候:就不用管最后一个元素了
12,45,55,73,36
......
12,45,55,36,73       这样第二大元素也跑到了最后

第三次再循环的时候:最后2个元素都不用管了
12,45,55,36,
......
12,45,36,55      这样第三大元素也跑到了最后

依次类推......

再把思路转换成代码。。。。。。

vs2017下的代码如下:
#include <stdio.h>

int main()
{
  int a[] = { 32, 85, 98, 12, 56, 47, 654 , -789, 10 };
  int i, j;
  int max = sizeof(a) / sizeof(a[0]);

  for (i = 0; i < max; i++)
  {
    for (j = 1; j < max - i; j++)
    {
      if (a[j - 1] > a[j]) //前面的元素大于后面的元素时,大的放在后面,从小到大,两个元素交换
      {
        //int tmp = a[j - 1];
        //a[j - 1] = a[j];
        //a[j] = tmp;

        int tmp = a[j];
        a[j] = a[j - 1];
        a[j - 1] = tmp;
      }
    }
  }
  for (i = 0; i < max; i++)
  {
    printf("a[%d] = %d\n", i, a[i]);
  }

  return 0;
}

-----------------------------------------------------------------------------
小注意事项:
int i = 10;
int a[i];   //这种定义数组的方法在过去的c标准中不能被支持,但C99以后的编译器可以支持这种语法,一般最好不要这样写。

int a[10];       //但可以这样写

#define NUM 100   //也可以这样写
int a[NUM];

=============================================================================
二维数组:本质一下子可以定义多个一维数组。

int a1[10];     //a1是一个一维数组,一维数组的数组名是a1。
int a2[2][10];   //a2是一个二维数组,二维数组的数组名是a2,这个二维数组中包含2个一维数组,分别是a2[0]、a2[1](注意a2[0]、a2[1]是一维数组的数组名),a2[0]和a2[1]这2个数组是连续的。
int a3[3][10];   //a3是一个二维数组,二维数组的数组名是a3,这个二维数组中包含3个一维数组,分别是a3[0]、a2[1]、a3[2](注意a3[0]、a3[1]、a3[2]是一维数组的数组名),a3[0]、a3[1]、a3[2]这3个数组是连续的。

再次复习:数组名:在c语言中数组名其实就是数组第一个元素的地址,是一个常量。常量是不可以做左值的。
-----------------------------------------------------------------------------
对于下面而言:
int a2[2][10];
printf("%u, &u, %u\n", sizeof(a2), sizeof(a2[0]), sizeof(a2[0][0]));
printf("%p, %p, %p\n", a2, a2[0], &a2[0][0]);   //三个值是一样一样的!!!

-->sizeof(a2);           //80 a2是二维数组名,sizeof(a2);该句的意思是:二维数组的大小
* * * * * * * * * *
* * * * * * * * * *

一维数组  -->sizeof(a2[0]);      //40 a2[0]是一维数组名,sizeof(a2[0]);该句的意思是:一维数组的大小
* * * * * * * * * *

二维数组  -->sizeof(a2[0][0]);  //4 a2[0][0]是二维数组中的某一元素(注意:也即一维数组的某一元素哦!),sizeof(a2[0][0]);该句的意思是:二维数组中的某一元素的大小(注意:也即一维数组的某一元素的大小)
* - - - - - - - - -
- - - - - - - - - -

-----------------------------------------------------------------------------
注意:是竖着排列的哦!!!
int a4[3][4][10];   //这是一个三维数组,有3个二维数组,二维数组名分别是:a4[0]、a4[1]、a4[2],每个二维数组中有4个一维数组,其中一个二维数组的一维数组的数组名分别是:a4[0][0]、a4[0][1]、a4[0][2]、a4[0][3]
三维数组:本质就是多个二维数组
- - - - - - - - - -   - - - - - - - - - -   - - - - - - - - - -    
- - - - - - - - - -   - - - - - - - - - -   - - - - - - - - - - 
- - - - - - - - - -   - - - - - - - - - -   - - - - - - - - - - 
- - - - - - - - - -   - - - - - - - - - -   - - - - - - - - - - 
-----------------------------------------------------------------------------
三维数组初始化:要特别特别注意:二维数组有两种输出的排列方式:

例如对于int a5[2][3][4];

- - - -  - - - -    - - - -   -->横着看,是一个二维数组,包含3个一维数组
- - - -  - - - -    - - - -      -->横着看,是一个二维数组,包含3个一维数组

竖着看        竖着看
- - - -         - - - -
- - - -         - - - -
- - - -         - - - -
是一个二维数组      是一个二维数组


int a5[2][3][4] = { { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} },
       { {13, 14, 15, 16}, {17, 18, 19, 20}, {21, 22, 23, 24} } };

int a5[2][3][4] = { 0 };

遍历三维数组的核心代码:(注意:打印的出来的横着看的哦!!!)
int i, j, k;
for (i = 0; i < 2; i++)
{
  for (j = 0; j < 3; j++)
  {
    for (k = 0; k < 4; k++)
    {
      printf("a[%d][%d][%d] = %d,", i, j, k, a[i][j][k]);
    }
    printf("\t");
  }
  printf("\n");
}

-----------------------------------------------------------------------------
二维数组的初始化

int a1[3][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} };
int a2[3][4] = { {1, 2, 3, 4},{5, 6, 7, 8} };   //第三个数组默认置为0
int a3[3][4] = { 0 };   //将所有的成员都初始化为0
int a4[][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}, { 8, 5, 9, 7}, {6, 8, 1, 2}};   //一维数组的个数不定

遍历二维数组的核心代码:
for (i = 0; i < sizeof(a4) / sizeof(a4[0]); i++)
{
  for (j = 0; j < sizeof(a4[0]) / sizeof(a4[0][0]); j++ )
  {
    printf("a4[%d][%d] = %d\t", i, j, a3[i][j]);
  }
  printf("\n");
}
-----------------------------------------------------------------------------
三维数组排序:把整个三维数组的所有成员进行排序

思路:(核心思想就是:降维或者称之为:抽象为一维数组)
1、遍历三维数组后,把这个三维数组所有元素提出放到一个一维数组里面,得到一个一维数组;
2、把这个得到的一维数组进行排序(使用冒泡排序);
3、把排序后的一维数组再放回到原来的三维数组里;
4、为了看的见,再次遍历打印这个新的三维数组。

vs2017下的代码如下:
#include <stdio.h>

int main()
{
  int a[2][3][5] = { { {5,1,2,4,89}, {45,21,10,20,22}, {45,210,123,587,456}}, { {52,45,879,410,230}, {456,85,51,65,96}, {87,45,10,21,22}} };
  int b[30] = { 0 };
  int i, j, k;
  int index =0;
  //1、遍历三维数组后,把这个三维数组所有元素提出放到一个一维数组里面,得到一个一维数组;
  for (i = 0; i < 2; i++)
  {
    for (j = 0; j < 3; j++)
    {
      for (k = 0; k < 5; k++)
      {
        b[index] = a[i][j][k];
        index++;
      }
    }
  }
  //2、把这个得到的一维数组进行排序(使用冒泡排序);
  for (i = 0; i < 30; i++)
  {
    for (j = 1; j < 30 - i; j++)
    {
      if (b[j - 1] > b[j])
      {
        int tmp = b[j-1];
        b[j - 1] = b[j];
        b[j] = tmp;
      }
    }
  }
  //3、把排序后的一维数组再放回到原来的三维数组里;
  index = 0;
  for (i = 0; i < 2; i++)
  {
    for (j = 0; j < 3; j++)
    {
      for (k = 0; k < 5; k++)
      {
        a[i][j][k] = b[index];
        index++;
      }
    }
  }
  //4、为了看的见,再次遍历打印这个新的三维数组。
  for (i = 0; i < 2; i++)
  {
    for (j = 0; j < 3; j++)
    {
      for (k = 0; k < 5; k++)
      {
        printf("a[%d][%d][%d] = %d\n", i, j, k, a[i][j][k]);
      }
    }
  }

  return 0;
}

=============================================================================
字符串与字符数组

字符串定义: 字符串是内存中一段连续的char空间,以 '\0' 结尾。
字符数组定义: 字符数组也是内存中一段连续的char空间哦!(特别注意:字符数组并不)
所以在c语言中,字符串和字符数组有着千丝万缕的联系,特别相似,有时都是通用的哦!

举例子如下:
char a[10];   //定义了一个字符类型的数组
a[0] = 'a';
a[1] = 'b';
a[2] = 'c';
a[3] = '\0';   //注意:0就是'\0'的ASCII码哦!!!所以 a[3] = '\0'; 等价于 a[3] = 0;
printf("%s\n", a);    //输出的是 abc
printf("%s\n", "abc");   //输出的是 abc
说明了 char a[10];虽然是一个字符数组,但是它符合c语言中关于字符串的描述。
其实呢,c语言中并没有单独的字符串类型,字符串类型其实就是靠字符数组来表达的。

char a[10] = "aabbcc";//此为简化的写法。其实理应该一个个的赋值那样复杂的写会更好的。初始化数组成员,注意:不能理解成定义的字符数组就等于右边的字符串啊!!!
a = "hello";   //不能这样写,给数组名赋值
-----------------------------------------------------------------------------
字符数组的初始化
举例子如下:
  初始化的时候,如果后面的值不写的话,默认都是0。
  char a[10] ={ 'a', 'b', 'c'}; //复杂啰嗦的写法,更直观
  //a[0] = 'a';
  //a[1] = 'b';
  //a[2] = 'c';
  //a[3] = '\0'; //注意:0就是'\0'的ASCII码哦!!!所以 a[3] = '\0'; 等价于 a[3] = 0;
  char a[10] = "abc"; //简化写法,更抽象,少写一个是一个,哈哈哈!!!
  char a[] = "abc"; //注意这个字符数组有4个成员变量哦~

  //把一个字符数组所有成员都初始化为0(或叫初始化为空串),有以下两种写法哦~
  char a[10] = { 0 }; 或者 char a[10] = { '\0' };
  char a[10] = ""; //如果是空串,什么都没有,说明里面只有一个 '\0'(或0) 哦~

超级特别注意:0就是'\0'的ASCII码,即他们俩是等价的,但是具体含义不一样哦~

char a[12] = "hello world";
int i;
for (i =0; i < sizeof(a); i++)
{
  printf("%d\n", a[i]); //打印的结果为 104 101 108 108 111 32 119 111 114 108 100 0  注意:空格的ASCII是32,'\0'字符零的ASCII是0。
}
-----------------------------------------------------------------------------
字符数组的使用(以及字符数组和字符串的区别)

在c语言中,没有字符串这种数据类型,可以通过char的数组来替代,字符串就是以0结尾的char的数组。

如果有一个char的数组,但不是以'\0'(字符零或者0)结尾的,那么这个数组就一定不是一个字符串,所以字符串是一种特殊的char的数组。

特别注意:(小心理解有偏差哦!!!)一个char的数组中可以出现多个字符零,但一个字符串中只能有一个字符零。

所以说当我们用一个字符数组的时候,要明确的知道,该字符数组什么时候可以当一个字符串用,什么时候当一个数组使用。

举例子如下:
  char a[7] = "hello";
  a[3] = '\0'; //等价于a[index] = 0;对于字符串来讲,是"hel",对于字符数组来讲,它的成员数量没有变化,还是7个。
  //print("%s\n", a); //输出的是:hel

  a[3] = 'l';
  a[5] = 'a';
  a[6] = 'a'; //这个时候a还是一个字符数组,但已经不是一个字符串了,因为结尾没有以0结尾了,不符合c语言对字符串的定义和要求了。
  printf("%s\n", a); //输出的是:helloaa烫烫滔窓

我的GitHub地址: https://github.com/heizemingjun
我的博客园地址: http://www.cnblogs.com/chenmingjun
我的蚂蚁笔记博客地址: http://blog.leanote.com/chenmingjun
Copyright ©2018 黑泽明军
【转载文章务必保留出处和署名,谢谢!】
相关文章
|
9天前
|
存储 编译器 C语言
【C语言基础考研向】09 一维数组
数组是一种有序集合,用于存储相同类型的数据,便于统一操作与管理。例如,将衣柜底层划分为10个格子存放鞋子,便于快速定位。在C语言中,数组定义格式为 `类型说明符数组名[常量表达式];`,如 `int a[10];` 表示定义了一个包含10个整数的数组。数组初始化时可以直接赋值,也可以部分赋值,且数组长度必须固定。数组在内存中连续存储,访问时需注意下标范围,避免越界导致数据异常。数组作为参数传递时,传递的是首地址,修改会影响原数组。
|
9天前
|
存储 C语言
【C语言基础考研向】10 字符数组初始化及传递和scanf 读取字符串
本文介绍了C语言中字符数组的初始化方法及其在函数间传递的注意事项。字符数组初始化有两种方式:逐个字符赋值或整体初始化字符串。实际工作中常用后者,如`char c[10]=&quot;hello&quot;`。示例代码展示了如何初始化及传递字符数组,并解释了为何未正确添加结束符`\0`会导致乱码。此外,还讨论了`scanf`函数读取字符串时忽略空格和回车的特点。
|
9天前
|
存储 Serverless C语言
【C语言基础考研向】11 gets函数与puts函数及str系列字符串操作函数
本文介绍了C语言中的`gets`和`puts`函数,`gets`用于从标准输入读取字符串直至换行符,并自动添加字符串结束标志`\0`。`puts`则用于向标准输出打印字符串并自动换行。此外,文章还详细讲解了`str`系列字符串操作函数,包括统计字符串长度的`strlen`、复制字符串的`strcpy`、比较字符串的`strcmp`以及拼接字符串的`strcat`。通过示例代码展示了这些函数的具体应用及注意事项。
|
12天前
|
存储 人工智能 C语言
C语言程序设计核心详解 第八章 指针超详细讲解_指针变量_二维数组指针_指向字符串指针
本文详细讲解了C语言中的指针,包括指针变量的定义与引用、指向数组及字符串的指针变量等。首先介绍了指针变量的基本概念和定义格式,随后通过多个示例展示了如何使用指针变量来操作普通变量、数组和字符串。文章还深入探讨了指向函数的指针变量以及指针数组的概念,并解释了空指针的意义和使用场景。通过丰富的代码示例和图形化展示,帮助读者更好地理解和掌握C语言中的指针知识。
|
12天前
|
存储 人工智能 C语言
C语言程序设计核心详解 第六章 数组_一维数组_二维数组_字符数组详解
本章介绍了C语言中的数组概念及应用。数组是一种存储同一类型数据的线性结构,通过下标访问元素。一维数组定义需指定长度,如`int a[10]`,并遵循命名规则。数组元素初始化可使用 `{}`,多余初值补0,少则随机。二维数组扩展了维度,定义形式为`int a[3][4]`,按行优先顺序存储。字符数组用于存储字符串,初始化时需添加结束符`\0`。此外,介绍了字符串处理函数,如`strcat()`、`strcpy()`、`strcmp()` 和 `strlen()`,用于拼接、复制、比较和计算字符串长度。
|
17天前
|
C语言
C语言 字符串操作函数
本文档详细介绍了多个常用的字符串操作函数,包括 `strlen`、`strcpy`、`strncpy`、`strcat`、`strncat`、`strcmp`、`strncpy`、`sprintf`、`itoa`、`strchr`、`strspn`、`strcspn`、`strstr` 和 `strtok`。每个函数均提供了语法说明、参数解释、返回值描述及示例代码。此外,还给出了部分函数的自实现版本,帮助读者深入理解其工作原理。通过这些函数,可以轻松地进行字符串长度计算、复制、连接、比较等操作。
|
30天前
|
存储 编译器 数据处理
【编程秘籍】解锁C语言数组的奥秘:从零开始,深入浅出,带你领略数组的魅力与实战技巧!
【8月更文挑战第22天】数组是C语言中存储同类型元素的基本结构。本文从定义出发,详述数组声明、初始化与访问。示例展示如何声明如`int numbers[5];`的数组,并通过下标访问元素。初始化可在声明时进行,如`int numbers[] = {1,2,3,4,5};`,编译器自动计算大小。初始化时未指定的元素默认为0。通过循环可遍历数组,数组名视为指向首元素的指针,方便传递给函数。多维数组表示矩阵,如`int matrix[3][4];`。动态数组利用`malloc()`分配内存,需用`free()`释放以避免内存泄漏。掌握这些技巧是高效数据处理的基础。
50 2
|
1月前
|
C语言
【C语言】字符串及其函数速览
【C语言】字符串及其函数速览
23 4
|
29天前
|
存储 算法 搜索推荐
C语言中数组
C语言中数组
33 0
|
1月前
|
C语言
【C语言篇】字符和字符串以及内存函数详细介绍与模拟实现(下篇)
perror函数打印完参数部分的字符串后,再打印⼀个冒号和⼀个空格,再打印错误信息。