C语言学习 -- 数组

一、一维数组

定义:类型说明符 数组名[常量表达式]
例:int a[10]; //10表示数组长度,有十个元素
访问a[10],没有这个元素,只有a[0]~a[9]
a[0]一定存放在低地址
a[9]一定存放在高地址

1.数组初始化:

int a[10] = { 1,2,3,4,5,6,7,8,9,10};
局部变量:int a[10]; //未初始化的局部变量是垃圾值
全局变量:int a[10]; //未初始化的全局变量是0
int a[10] = {1,2,3}; //对部分元素初始化,未初始化的元素变为0
int a[10] = {0}; //所有元素初始化为0
int a[] = {1,2,3,4,5,6,7,8,9,10}; //可以不指定数组长度,但是一定要初始化

#include 

//int a[10];                                       //未初始化的全局变量是0

int main()
{
#if 0
	int a[10];                                     //定义有10个整型元素的数组,在内存里面连续存储
	//int a[0];                                    //错误
	int k;
	//int b[k] = {0};                              //错误,数组的长度一定是确定的
#endif

//数组的初始化操作
	//int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};  //对所有元素初始化
	//int a[10];                                    //没有初始化,未初始化的局部变量是垃圾值
	//int a[10] = {1, 2, 3};                        //对部分元素初始化,没有初始化的元素变成0
	//int a[] = {1, 2, 3, 4, 5, 6 ,8, 8};           //可以不指定数组长度,但是一定要初始化
	int a[10] = {0};                                //所有元素初始化成0
	
	//printf("%d\n", a);  //错误,不能直接输出整型数组
	int i;
	for (i = 0; i < sizeof(a) / sizeof(int); i++)
	{
		printf("%d ", a[i]);
	}
	printf("\n");

	printf("%p\n", &a[0]);   //输出数组a首元素的地址
	printf("%p\n", a);   //a表示数组首元素地址,和&a[0]意义一样
	printf("%p\n", &a);  //&a表示数组的地址

	printf("*********\n");
	printf("%p\n", &a[0] + 1);
	printf("%p\n", a + 1);
	printf("%p\n", &a + 1);

	return 0;
}

2.冒泡排序法

#include 

#define SIZE  10

int main()
{
	int a[SIZE] = {0};
	int i, j, tmp;

	for (i = 0; i < SIZE; i++)
	{
		scanf("%d", &a[i]);
	}

	for (i = 0; i < SIZE - 1; i++)
	{
		for (j = 0; j < SIZE - 1 - i; j++)
		{
			if (a[j] > a[j + 1])    //从小到大排序
			{
				tmp = a[j];
				a[j] = a[j + 1];
				a[j + 1] = tmp;
			}
		}
	}

	for (i = 0; i < SIZE; i++)
	{
		printf("%d ", a[i]);
	}
	printf("\n");

	return 0;
}

二、二维数组

1.概念

a[3][4] //三行四列的数组

a[0][0] a[0][1] a[0][2] a[0][3]
a[1][0] a[1][1] a[1][2] a[1][3]
a[2][0] a[2][1] a[2][2] a[2][3]

#include 

int main()
{
	int i, j;
	//int a[3][4];                 //三行四列的二维数组
	//int a[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};   //对所有元素初始化
	//int a[3][4] = {1, 2, 3, 4, 5}; //对部分元素初始化
	//int a[][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
	int a[3][4] = {0};           //整个数组初始化成0

	for (i = 0; i < 3; i++)      //行循环
	{
		for (j = 0; j < 4; j++)  //列循环
		{
			printf("%d ", a[i][j]);
		}
		printf("\n");            //每行结束打印换行
	}

	printf("%p\n", &a[0][0]);     //第一个元素的地址
	printf("%p\n", a);            //数组名
	printf("%p\n", &a);
	printf("%p\n", a[0]);
	printf("%p\n", &a[0]);
	printf("*************************\n");
	printf("%p\n", &a[0][0] + 1);     //第一个元素的地址,单位是一个元素,四个字节
	printf("%p\n", a + 1);            //数组名,数组首行地址,单位是一行
	printf("%p\n", &a + 1);           //数组的地址,单位是一个数组
	printf("%p\n", a[0] + 1);         //数组首行首元素地址,单位是一个元素
	printf("%p\n", &a[0] + 1);        //数组首行地址

	/*
				&a      数组名,数组地址
				*(&a)   数组首行地址
				a       数组首行地址
				*a      数组首行元素地址
	*/

	return 0;
}

2.字符数组

#include 

int main()
{
	int i;
	//char a[10] = {'h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd'};
	char b[15] = "helloworld";

	/*char c[15];
	c = "helloworld";*/

	/*for (i = 0; i < 10; i++)
	{
		printf("%c", a[i]);
	}
	printf("\n");*/
	printf("%s\n", b);  //遇到'\0'结束

	return 0;
}

3.字符串处理函数

#include 
#include 

int main()
{
	char a[32] = {0};                //初始化字符数组  char a[32] = {'\0'};
	char b[32] = "hellwoorld";    
	char c[32] = "123451234512345";

	/*char d[32];   //d是数组名 是数组首元素低地址 是常指针
	d = "helloworld";
	d[32] = "helloworld";*/

	//strcpy(a, b);  //字符串拷贝函数,把数组b中的字符串拷贝到数组a中
	//strcpy(c, b);  //包括'\0',所以是全部覆盖
	//strcpy(a, "helloworld");
	//printf("%s\n", a);
	//printf("%s\n", c);

	//strcat(b, c);  //字符串连接函数 把字符串c连接到字符串b后面
	//strcat(b, "111111");
	//strcat("11111", b);   //错误
	//printf("%s\n", b);

	if (strcmp(b, c) > 0)    //字符串比较函数 返回值 b>c 返回值大于0, b==c 返回值等于0 b c\n");
	}

	if (strcmp(b, "helloworld") > 0)
	{
		printf("b > hello\n");
	}

	return 0;
}

4.自定义函数

实参和形参要求:个数相同、类型相同、顺序相同、名字可以不同
函数名也是地址
函数调用:
1.通过函数名找到函数入口地址
2.给形参分配空间
3.传参(值传递、地址传递)
4.执行函数体
5.返回
6.释放空间(栈空间)

#include 

void swap(int *x, int *y);  //函数声明,如果函数定义 在 函数调用 的下面

void print()   //函数类型void 表示没有返回值   没有形参
{
	printf("helloworld!\n");  //函数体
}

int add(int x, int y)  //x和y 形参(形式参数)  实参和形参个数相同、类型相同、顺序相同、名字可以不同 
{                      //2、给形参分配空间(栈空间)  3、传参(值传递、地址传递)
	//return x + y;
	int sum;           //4、执行函数体

	sum = x + y;

	return sum;   //返回结果    //5、返回
}                               //6、释放空间(栈空间)!!!!!

int main()
{
	int a = 1, b = 2;
	int result;

	print();                   //1、通过函数名找到函数入口地址
	result = add(a, b);        //a和b 实参(实际参数) 实参不要加类型
	printf("%d\n", result);
	printf("%d\n", add(a, b));
	printf("%p\n", add);       //函数名也是地址

	swap(&a, &b);   //当涉及修改实参值得时候,需要传地址
	printf("a = %d b = %d\n", a, b);

	return 0;
}

void swap(int *x, int *y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}

注:
当涉及修改实参值得时候,需要传地址

5.关键字

register

#include 

int main()
{
	register int i;   //寄存器变量,i存放在寄存器中

	for (i = 0; i < 100000; i++)  //循环次数比较多的循环变量,可以使用register修饰
	{
		
	}

	//&i;   //i存放在寄存器中,&取的是内存的地址

	return 0;
}

static

#include 

void f()
{
	static int a = 0;   //3、修饰局部变量:改变变量的生命周期,直到程序结束才被释放(存放的位置不一样,不加
						//static修饰,存放在栈空间,加上static修饰,存放在数据段(静态数据区))
	a++;
	printf("%d\n", a);
}

int main()
{
	int i;

	for (i = 0; i < 5; i++)
	{
		f();
	}

	return 0;
}

宏函数

#include 

#define OUT   printf("helloworld\n")    //无参宏函数
#define P(s)  printf("%s\n", s)         //有参宏函数
#define SQR(x)  (x) * (x)               //宏函数只是简单的替换,注意优先级

/*
宏函数的优点:
1、节省空间(不需要给形参分配空间)
2、执行效率高(不需要根据地址找到函数的入口)

宏函数的缺点:
1、编译效率低(第一步预处理需要替换)
2、不安全,只是简单的替换,没有语法检查
*/

int main()
{
	int a = 1, b = 2;
	OUT;
	P("12345");
	printf("%d\n", SQR(a + b));   //1 + 2 * 1 + 2

	return 0;
}

extern

//static int num = 100;   //1、修饰全局变量:改变变量的作用域,只能在本文件中被使用,不能在其他文件中使用
int num = 100;

int main()
{
	print();

	return 0;
}


#include 

extern int num;     //声明外部变量,告诉编译器num在其他文件中被定义
					//声明:不用分配空间
					//定义:分配空间

//static void print()  //2、修饰函数:改变函数的作用域,只能在本文件中被调用,不能在其他文件中调用
void print()
{
	printf("%d\n", num);
}


你可能感兴趣的:(C语言学习 -- 数组)