C语言基础学习

数组
数组:一组数,一组相同类型元素的集合。(是同类型变量的集合,共用一个名字用下标区分)
每一个变量称作数组元素
:一维数组对应数学中的数列,二维数组对应矩阵
语法结构(定义):元素类型+arrname数组名[数组大小(一定是常量表达式)] 尤其const修饰的常变量
是一个误区
(只有c99的语言标准才支持放变量)按照下标顺序在内存中存放
注:一维数组与数学中的数列对应,二维数组与矩阵对应
一维数组的定义:格式:类型说明符 数组名字[常量表达式];(常量表达式不能进行动态定义即大于0的
正整数) 数组名就是数组,数组名[常量表达式]为数组元素等价于普通变量
例:int arr a[8];
char arr b[8];
注意:数组必须先定义后使用
数组元素表达形式,数组名[下标]下标从0开始
只能单独应用数组元素, 不能一次性引用整个数组
下标只能是整型常量或者整型表达式,数组元素在功能是等价于一个普通的变量
一维数组的初始化:(数组不初始化,其元素值为随机数)
1:完全初始化: int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
2:不完全初始化 int arr[10] = { 1,2,3,4,5 };只有前五个有赋值
当[]里面不写数字下面两个等效
int arr[] = { 1,2,3,4,5 };
int arr[5] = { 1,2,3,4,5 };根据初始化确定个数(编译器根据初值个数确定数组长度)
也可以对部分数组元素进行初始化: int arr[6] = { 1,2,3,4,5 };
字符数组初始化;
字符数组的输入输出: 逐个字符%c,整个字符串%s 数组名表示首元素地址前面不可以加& 输入串函数小于
数组长度遇到空格回车自动结束
其中arr与&arr[0]等价
char ch[5] = { 'a' , 'b' , 'c' }; 单引号一个一个往进去放 \0没有\0程序就不能停止下来是乱码
char ch[] = { 'a' , 'b' , 'c' };此时[]只有3
第二种写法 char ch[] = "abc" ;相当于a,b,c,\0相当于后面可以确定前面的
两种写法的区别 char ch[5]={} char ch[] = ""第一个打印出来有随机值
用{}的时候需要以\0结尾 ""他内部自己就有\0
一维数组的使用
[]下标引用操作符数组通过下标开始访问,默认从0开始
#include(一次性输入)
int main()
{
int i = 0;
int a[10] ;
printf("输入10个数字");
scanf_s("%s", a);一次性输入数组的时候数组名就是地址所以只要写数组名就行了此时是数
组名
for (i = 0; i <= 9; i++)
printf("%d\n", a[i]);
}
#include (单个单个输入)
int main()
{
int i = 0;
int a[3] = { 0 };
for(i=0;i<3;i++)
{
scanf("%d",&a[i]); 此时输入的是整型此时 a[i] 相当于一个普通变量
}
for(i=0;i<3;i++)
{
printf("%d",a[i]);
}
}
//一维数组
#include
#include
int main()
{
int arr[10] = { 0 };
arr[4] = 7;
char ch1[] = { 'a','b','c' };
int i = 0;
char ch2[] = "abc";
printf("%s\n", ch1);
printf("%s\n", ch2);
printf("%d\n", strlen(ch1));
printf("%d\n", strlen(ch2));
for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
}
冒泡法(把两个相邻数比较,小的调到前面)
#include void Bubble_sort(int arr[], int size)
{
int j,i,tem;
for (i = 0; i < size-1;i ++)//size-1 是因为不用与自己比较,所以比的数就少一个
{
int count = 0;
for (j = 0; j < size-1 - i; j++) //size-1-i 是因为每一趟就会少一个数比较
{
if (arr[j] > arr[j+1])// 这是升序排法,前一个数和后一个数比较,如果前数大则
与后一个数换位置
{
tem = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tem;
count = 1;
}
}
if (count == 0) // 如果某一趟没有交换位置,则说明已经排好序,直接退
出循环
break;
}
}
int main()
{
int arr[10];
int i;
printf(" 请输入 10 个数 \n");
for (i = 0; i < 10; i++) // 接收用户的数值
{
scanf("%d", &arr[i]);
}
printf(" 排序前的数组 >");
for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
printf("\n 排序后的数组 >");
Bubble_sort(arr, 10);
for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
用数组求fibonaccci数列的前二十个数字
#include
int main()
{
int i=0;
int a[20]={1,1};
for(i=2;i<=20;i++)
{
a[i]=a[i-1]+a[i-2];
}
printf("%s",a); }
一维数组在内存中的存储:
%p以地址的形式打印十六进制打印
int main()
{
int arr[10] = { 0 };
int i = 0;
for (i = 0; i < 10; i++)
{
printf("&arr[%d}=%p\n", i, &arr[i]);
}
}
结论:一维数组在内存中是连续存放的,随着下标的增长,地址是由低到高变化的
数组名是首元素地址
二维数组:有行有列等价于数学里面的矩阵(C语言中允许定义多维数组三维乃至n维)
定义:类型+数组名[常量表达式1][常量表达式2](二维数组是由行个一维数组组成的)
int arr[3][4];
int a[0][0]
int a[0][1]
int a[0][2]
int a[0][3]
int a[1][0]
int a[1][1]
int a[1][2]
int a[1][3]
int a[2][0]
int a[2][1]
int a[2][2]
int a[2][3]
二维数组的初始化: 初始化即创建的同时给他赋值
相当于放满不完全初始化-后面补零
部分初始化:int a[3][3]={{1},{0,1},{0,0,1}};相当于矩阵
1
0
0
0
1
0
0
0
1
第一种写法:int arr[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12,};
1
2
3
4
5
6
7
8 9
10
11
12
第二种办法 int arr[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}} ;
行可以省略但是列 不可以
二维数组的使用:
行号从0开始,列号也从0开始和一位数组类似
打印一个二维数组的所有数
#include
int main()
{
int arr[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12, };
int i = 0;
int j = 0;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 4; j++)
{
printf("%d", arr[i][j]);
}
printf("\n");
}
}
二维数组在数组中的存储
#include
int main()
{
int arr[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12, };
int i = 0;
int j = 0;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 4; j++)
{
printf("&arr[%d][%d]=%p\n", i, j, &arr[i][j]);
}
printf("\n");
}
}
结论:二维数组在内存中也是连续存在的,一行是连续的,跨行也是连续的
数组作为函数参数
数组传参其实传的是首元素的地址,传过去的不可以计算大小
数组名是首元素的地址
(有两个例外, 一个是sizeof内部放一个表示整个数组的大小单位是字节
2,取地址数组名此时数组名表示整个数组)
冒泡排序:思想是两两相邻元素进行比较并且可能需要交换(指针可以传地址)
#include
void bubble_sort(int arr[], int x)//本质是指针,一个指针变量的的大小是4个字节
{
int i = 0;//趟数
for (i = 0; i < x - 1; i++)
{ // 一趟冒泡排序的过程
int j = 0;
for (j = 0; j < x - 1 - i; j++)
{
if (arr[j] > arr[j + 1])
{
int tem = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tem;
}
}
}
}
例:求二维数组中最大的元素值及其行列号
#include
void main()
{
int a[3][4] = { {1,2,3,4},{9,8,7,6},
{-10,10,-5,2} };
int i, j, row = 0, colum = 0, max;
max = a[0][0];随时随刻更新着max的值
for (i = 0; i <= 2; i++)
for (j = 0; j <= 3; j++)
if (a[i][j] > max)
{
max = a[i][j]; row = i; colum = j;
}
printf("max=%d,row=%d, \ colum=%d\n", max, row, colum);
将一个二维数组中的行列互换
#include
void main()
{
int a[2][3] = { {1,2,3},{4,5,6} };
int b[3][2], i, j;
printf("array a : \n");
for (i = 0; i <= 1; i++)
{
for (j = 0; j <= 2; j++)
{
printf(" % 5d", a[i][j]);
b[j][i] = a[i][j];
}
printf("\n");
}
printf("array b : \n");
for (i = 0; i <= 2; i++)
{
for (j = 0; j <= 1; j++)
printf(" % 5d", b[i][j]);
printf("\n");
}
}
常用的字符串处理函数
#include
字符串输入函数 gets 格式 gets(字符串数组名)从键盘输入以回车结束的字符串自动加\0
注: 输入串长度小于字符串长度
字符串输出函数 puts 格式 puts(字符串数组名)向显示器输出字符串(输出完自动换行) 注:字符数组必须以‘\0’结束
字符串连接函数 strcat 格式:strcat(字符数组1,字符数组2)
功能:把字符数组2连到字符数组1后面
返值:返回字符数组1的首地址
说明:字符数组1必须足够大
连接前,两串均以‘\0’结束;连接后,串1的‘\0’取消, 新串最后加‘\0’
字符串拷贝函数 strcpy 格式:strcpy(字符数组1,字符串2)
功能:将字符串2,拷贝到字符数组1中去
返值:返回字符数组1的首地址
说明:字符数组1必须足够大,拷贝时‘\0’一同拷贝,不能使用赋值语句为一个字符数组赋值
字符串长度函数 strlen 格式:strlen(字符数组)
功能:计算字符串长度 返值:返回字符串实际长度,不包括‘\0’在内
指针部分把c的地址赋值给变量p,我们称p为指向c的指针
编号-地址-指针(即内存单元的内存编号)指针大小在 32位是4个字节在64位是8个字节变量的地址由系
统分配程序只可使用不能修改
定义:数据类型 *指针名=初始地址(一般为&n);
int i=0;
int *p=&i;
int *q=p(因为p就是地址)
指针和指针变量 :指针:一个变量的地址 指针变量:专门存放变量地址的变量
直接访问:按变量地址存取变量值(直接使用变量)
间接访问:通过存放变量的地址的变量去访问变量(即通过指针变量去访问)
指针变量与变量之间的关系
i=*p &i=p i=3 等价于*i=3
注意:1、int *p1, *p2; 与 int p1, p2;
2、指针变量名是p1,p2 ,不是*p1,*p2
3、指针变量只能指向定义时所规定类型的变量
4、指针变量定义后,变量值不确定,应用前必须先赋值
&与*之间的关系(两者互为逆运算)
#include
void main()
{
int a;
int* pa = &a;
a = 10;
printf("a:%d\n", a);10
printf("*pa:%d\n", *pa);10
printf("&a:%d\n", &a);地址
printf("pa:%d\n", pa);地址
printf("&pa:%d\n", &pa);指针的地址
} *p指针的目标变量,他的内容是数据 p是指针变量他的内容是地址 &p指针变量占用内存的地址
指针:一个变量的地址 指针变量:专门存放变量地址的变量叫指针变量(就是用来存放地址的变量)
#include
int main()
{
int a = 10;//a占四个字节
int* pa = &a;//拿到的是四个字节中的第一个字节的地址
*pa = 20;
printf("%d\n", a);
return 0;
} %p打印地址的符号
指针和指针类型
指针类型大小一样
#include
int main()
{
int* pa;
int* pc;
int* pf;
printf("%d\n", sizeof(pa));
printf("%d\n", sizeof(pc));
printf("%d\n", sizeof(pf));
return 0;
}
一个十六进制位等于四个二进制位
指针类型的意义:权限有多大
1:指针类型决定了解引用的权限有多大(能操作几个字节)
2:指针类型决定了指针走一步走多远(步长)整型指针+1是四个字节,char+1是两个字节
int a = 0x11223344;
char b = 0x11223344;
int* pa = &a;
*pa = 0;
char* pc = &b;
*pc = 0;
return 0;
指针的解引用( 到底加几只和指针变量的类型有关系和指向谁没有关系
int arr[10] = { 0 };
int* p = arr;
int i = 0;
for (i = 0; i < 10; i++)
{
*(p + i) = 1;
}
指针变量作为函数参数(传递的是地址)由于C语言是以传值的方式将参数值传递给被调用函数
的,因此被调用函数不能直接修改主函数中变量的值。
特点:共享内存,双向传递
例:将数字由大到小输出
#include
void swap()
{
int p;
p = *p1;
*p1 = *p2;
*p2 = p;
}
void main() {
int a, b;
int* pointer_1, * pointer_2;
scanf("%d,%d", &a, &b);
pointer_1 = &a; pointer_2 = &b;
if (a < b)
swap(pointer_1, pointer_2);(写的是指针变量的名字)
printf("\n%d,%d\n", a, b);
}
优点:地址传递,指针变量所指向的变量的值发生变化,函数调用结束,值保留了下来。可以改
变主函数多个变量的值
指针都是先赋值后使用
数组的指针和指向数组的指针变量( 指针和数组
数组名:首元素的地址(首元素的首地址)
一:指向数组元素的指针
int a[10];
int * p;
p = &a[0];
int * p = &a[0];(a[0]是普通变量)
int * p = a;(数组名就是地址所以不需要加取地址符号)
#include
int main()
{
int arr[10]={0};
int i = 0;
int* p;
p = arr;
for (i = 0; i < 10; i++)
{
*(p + i) = i;
}
for (i = 0; i < 10; i++)
{
printf("%d",arr[i]);
}
}
指针的算数运算
p+i=p+i*d(d是类型字节数)
用指针引用数组元素
int a[10],*p=a;
地址p=a[0]=*p元素利用指针计算即可p+1=a[1]=*(p+1)
(变量才能实现自加运算,a为数组名是非变量)指针变量可以实现自己值的改变
一维数组作函数参数
数组名作函数参数是地址传递
对应关系
实参
形参 数组名
数组名
数组名
指针变量
指针变量
数组名
指针变量
指针变量
二级指针(本质上是因为指针变量他依然还是一个变量)

你可能感兴趣的:(c语言)