C程序设计基础(4):数组(数组声明与使用、数组内存操作)、字符串

  上一节中,我们学习了循环结构语句的作用及使用方法。但在一般解题过程中,常常会出现需要多组数据同时考虑的情况。这是,对一组大量数据一一声明并操作,显然不具有可行性,这时候,就需要使用数组来存放一系列数据。下面,我们将了解数组的概念,数组声明与使用,以及数组内存的操作(初始化,数组复制等)。后面,我们将顺带了解字符串相关内容。

Array

数组概念

  请大家先考虑以下数学中的数列,它们使用下标来区分其中元素。数组中元素的存储方式与数列相同,数组中的每一个元素都具有自己的唯一索引(即下标)。比如,n个元素的数组,索引为0~n-1。通过这个索引,可以定位到该元素,并对其进行读写操作。

  (本段原理内容仅供有兴趣的读者了解,不要求一定掌握)C语言中,数组的存储形式为一段连续的内存。数组声明时,系统将为这个数组分配一段连续的内存空间,大小为元素个数乘以元素数据类型,元素按照顺序存储在其中。实际上,数组本身(不加任何索引,仅数组名称)也是一个变量,它是一个指向数组的首部的指针(有关指针的内容将在后几节给出)。在调用一个数组元素时,系统通过数组下标和元素大小计算地址偏移量,再根据数组首部指针计算出数组元素的真实地址,就可以对这个地址上的数据进行操作。


数组操作

数组声明

  **与其他变量相同,数组在使用前需要进行声明。**声明语法:

type name[size];

其中,

  • type: 数组中元素的类型,一个数组中元素的类型只能有一个
  • name: 数组的名称,命名规则与变量相同
  • size: 数组的大小,注意:数组大小非数组最后一个元素的索引,实际索引为[0]到[size-1]

数组使用

语法示例:

int a[100];
a[0] = 1;

使用时,name[index]就可以指定一个数组中的一个元素,并能像变量一样操作。索引可以是一个变量或者一个表达式,其他用法与单个变量完全相同,这里就不赘述。

注意,如果想要将一个数组a赋值给另一个数组b,不能直接赋值,由于数组本身是一个指针,如果这样赋值,则会使数组b指针指向a,a和b将会是同一个数组,改变数组a元素,b也会改变。如果想要进行数组按值赋值,请见下文“内存赋值”

下面用一个样例展示数组与循环语句结合的用法,a[i]为从1加到i的和,

int a[100];
memset(a, 0, sizeof(a));
for (int i = 1; i < 100; i++)
    a[i] = a[i - 1] + i;

其中的memset语句将在下面的数组内存操作中讲到

多维数组

某些情况下,我们可能需要一个表来存储数据,这就用到了二维数组。通过数组声明,我们可以使用二维、三维甚至多维的数组。
使用多个方括号就可以声明和使用多维数组,下面用一个样例说明:

int a[100][100];
a[0][1] = 1;
printf("%d\n", a[0][1]);

数组内存操作

对数组内存的操作需要引用头文件string.h

内存赋值 memset

  新声明一个数组后,系统并不会自动清空这个位置上的原有数据,这时,不过不加初始化就读取,极有可能遇到意外情况(读取到一个无意义数据)(参考烫烫烫和屯屯屯等)。这就需要将整个数组进行初始化(一般为置零),memset语句就提供了整块内存赋值的功能。

memset(array_name, value, size);

其中:

  • array_name: 数组名称,也即数组指针
  • value: 要赋的值,一般为0,若不是,则在多字节变量中会遇到问题(下面会说到)
  • size: 要赋值的字节数,注意:是字节数而不是元素个数,字节数为元素个数和元素类型字节数的乘积

以下为示例,

int c[100];
memset(c, 0, sizeof(c));

其中,sizeof(c)语句获取了整个c数组的大小(已经乘过元素类型字节数)

注意:内存赋值时,是将所指定的每一字节都赋值为value,如果value不是0,则单字节变量不受影响,而多字节元素则会导致一个元素中的值不为value,假设value=1,赋值给双字节变量a[0],则有a[0]=0b0000000100000001=257.

内存复制 memcpy

  如果想要将一个数组的值复制给另一个数组,不能直接将两个数组指针变量进行赋值,那样只会导致地址传递,最后两个数组成为一个。需要使用下面要说的memcpy语句,

memcpy(Dst, Src, size);

其中:

  • Dst: 赋值的目标数组指针
  • Src: 赋值源数组指针
  • size: 需要复制的字节数(注意:是字节数

下面展示一个内存复制的样例

#include <stdio.h>
#include <string.h>

int main()
{
	int a[100], b[100];
	for (int i = 0; i < 100; i++)
		a[i] = i;
	memcpy(b, a, sizeof(a));

	for (int i = 0; i < 10; i++)
		printf("%d\n", b[i]);
	a[0] = 100;
	printf("a[0] is: %d\n", a[0]);
	printf("b[0] is: %d\n", b[0]);
	return 0;
}

从输出结果可以看出,数组a的所有值传给了数组b,并且,数组a中值的改变不会对b造成任何影响。


字符串

  实际上,字符串也是一个字符(char)类型的数组,字符串的每一个字符按位存储在数组中。字符串有效值的最后,需要有一个值为0的元素(结束符)来标志数组的结束。所以,字符串数组所能存储的最大字符数为数组长度减一。

字符串的声明和使用

字符串的声明和使用与普通数组完全相同,不过赋值时,可以直接给它赋一个用双引号包含的常量字符串,下面的示例将使用它,

char string[100];
memset(string, 0, sizeof(string));
string = "Hello World!\n";
printf("%s", string);

也可以使用一个字符串常量来对一个字符串变量进行初始化,这时候可以不指定数组长度,默认常量长度+1(结束标志)。

char string[] = "Hello";
printf("%d\n", sizeof(string));

字符串的输出和输出

字符串IO主要有两种方式:scanf/printfgets/puts

对于scanf/printf格式化输入输出:

语法示例:

printf("%s\n", string);
scanf("%s", string); //没有&
  • printf输出直接使用即可,转换说明为%s
  • scanf转换说明也是%s,但需要注意:
    • 由于数组变量就是一个指针,在scanf的参数位置不需要再加提领标识符&,示例:scanf("%s", string)
    • scanf仅能读取一段连续的字符串,遇到空字符串会停止,如"Hello world",只能读入"Hello"

对于gets/puts字符串输入输出

语法示例:

gets(string);
puts(string);
  • gets能够读取一整行内容,读到换行符或者EOF停止
  • puts能够输出一个字符串,最后将会附带一个\n换行符

字符串长度函数strlen

char string[] = "Hello World";
printf("%d\n", strlen(string));

strlen函数将返回字符串变量中真实字符串的长度(不包含结束符)。它将逐个搜索变量,直到找到一个值为0(字符串结束符)的位置,停止计数并返回。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值