C语言学习(5)

本文详细讲解了C语言中的数组概念、初始化方法,包括一维数组、字符数组和二维数组。深入剖析指针,包括基本原理、算术运算及指针数组,还介绍了结构体、共用体和回调函数。同时涵盖动态内存分配技巧,以及如何使用结构体实现面向对象思维。
摘要由CSDN通过智能技术生成
数组

(1)介绍
数组可以存放多个同一类型数据,数组也是一种数据类型,是构造类型。传递是以引用的方式传递(即地址传递)
(2)数组的定义

数据类型 数组名[数据大小]
int a[5]
1.数组名就代表该数组的首地址,即a[0]的地址
2.数组的各个元素是连续分布的,a[1]的地址=a[0]的地址+int的字节数(4),以此类推。
3.数组的下标从0开始
计算数组长度:
	int arrLen = sizeof(a)/sizeof(int)

(3)数组的初始化方式

//1
int nums[2];
nums[0]=1;
nums[1]=2;
//2
int nums[2]={1,2}
//3
int nums[]={1,2}

(4)数组的使用事项
1)数组是多个相同类型数据的组合,一个数组一旦声明,其长度是固定的,不能动态变换
2)数组创建后,如果没有赋值,全局数组默认值为0,非全局数组初值是机器垃圾(原来系统分配给这块空间的值)
3)使用数组的步骤1 定义数组;2 给数组各个元素赋值;3使用数组
4)数组的下标是从零开始的。
5)数组下标必须在指定范围内使用,编译通过;如超出范围,在运行时会因为数组越界而异常中断
6)C数组属于构造类型,是引用传递(传递的是地址),因此当把一个数组传递传递给一个函数时,函数操作数组会影响到原数组的值

字符数组

(1)基本介绍
用来存放字符的数组称为字符数组
字符数组实际上是一系列字符的集合,也就是字符串,在C语言中没有专门的字符串变量,通常就用一个字符数组来存放一个字符串。
注:
1)在C语言中,字符串实际上是使用null字符(‘\0’)终止的一维字符数组。因此,一个以null结尾的字符串,包含了组成字符串的字符
2)‘\0’是ASCLL码表中的第0个字符,用NULL表示,称为空字符。该字符既不能显示,也不是控制字符,输出该字符不会有任何效果,在C语言中仅作为字符串的结束标志。
注:
1)如果在给某个字符数组赋值时,赋给的元素的个数小于该数组长度,则会自动在后面加’\0’
2)赋给的元素个数等于该数组的长度,则不会自动添加’\0’
3)在定义字符数组时应估计实际字符串长度,保证数组长度始终大于字符串的实际长度,否则,在输出字符数组时可能出现未知符号。

char str[]="hello";
//这种方式定义的字符数组,会在字符结束后自动添加'\0',推荐使用
//此时的有效字符任然为字符个数,不包括'\0'
//但是不能使用以下方式初始化或赋值
char str[];
str = "hello";   //str是常量,不能更改其地址
//但是可以用以下方式
char str[2];
str[0]='h';

(2)字符串指针

char* pStr = “hello”;

注:
1)C语言对字符串常量是按字符数组处理的,在内存中开辟了一个字符数组用来存放字符串常量,程序在定义字符串指针变量pStr时只是将字符串首地址赋给pStr
2)pStr存放是字符串的首地址,重新赋值后,相当于将指向了另一块地址
3)如果定义了一个字符数字,那么它有确定的内存地址;而定义一个字符串指针变量时,它并未指向某个确定的字符数据,并且可以多次赋值

二维数组

1)语法:类型 数组名[大小][大小]
2)二维数组在内存的存在形式,各个元素的地址是连续分布的,即在前一个元素基础上加一个类型的字节大小
注:
1)可以只对部分元素赋值,未赋值的元素自动取“零”值
2)如果对全部元素赋值,那么第一维的长度可以不给出
3)二维数组可以看作是由一位数组嵌套而成的;如果一个数组的每一个元素又是一个数组,那么它就是二维数组

指针(详解)

(1)基本介绍
1)指针,就是内存的地址:所谓的指针变量,就是保存了内存地址的变量。
2)获取变量的地址,用&
3)指针类型。指针变量存放的是一个地址,这个地址指向的空间存的才是值
4)获取指针类型所指向的值,用*
5)指针是一个变量,其值为另一个变量的地址。就像其他变量或常量一样,在使用指针存储其他变量地址之前,对其进行声明。
(2)指针的算数运算
1)++、- -
当指针进行++/–时,指针会按照它指向的数据类型字节数大小增加或减少,如int*指针,每++,就增加4个字节。

int arr[]={10, 100, 200};
int*ptr;
ptr = arr;

在这里插入图片描述

ptr++;
*ptr就是arr[1]

在这里插入图片描述

2)+、-
当可以对指针按照指定的字节数大小进行+或者-,可以快速定位你要的地址
3)指针是可以使用比较运算符进行比较的

(2)指针数组
1)基本介绍
要让数组的元素指向int或其他数据类型的地址(指针)
2)指针数组的定义
数据类型 *指针数组名[大小]

int *ptr[3]
//ptr声明为一个指针数组
//由3个整数指针构成。ptr中的每个元素,都是指向int值的指针。

(3)多重指针
指向指针的指针是一种多级间接寻址的形式,或者说是一个指针链。通常,一个指针包含一个变量的地址。当我们定义一个指向指针的指针时,第一个指针包含了一二个指针的地址,第二个指针指向包含实际值的位置
注:
1)一个指向指针的指针变量必须如下声明,即在变量名前放置两个型号。例如:int **
2)当一个目标值被一个指针间接指向到另一个指针时,访问这个值需要使用两个星号。如**ptr

(4)返回指针的函数
C语言中允许函数返回指针类型数据,即指针函数
注:
1)用指针作为函数的返回值时需要注意,函数运行结束后会销毁在它内部定义的所有局部数据,包括局部变量、局部数组和形参,函数返回的指针不饿能指向这些数据。
2)函数运行结束后销毁该函数所有的局部数据,这里的销毁并不是将局部数据占用的内存全部清零,而是程序放弃对它的使用权限,后面的代码可以使用这块内存(重置这块空间存放的内容)
3)C语言不支持在调用函数时返回局部变量的地址,如果确实有这样的需要,需要定义局部变量为static变量
(5)函数指针
1)基本介绍
a.一个函数总是占用一段连续的内存区域,函数名在表达式中有时也会被转换成为该函数的首地址,这个和数组名非常类似
b.把函数的首地址(入口地址)赋予一个指针变量,使指针变量指向函数所在的内存区域,然后通过指针变量就可以找到并调用该函数,这种指针就是函数指针
2)函数指针的定义

//returnType (*pointerName)(param list)
//returnType为函数返回值类型
//pointerName为指针名称
//param list为函数参数列表
//参数列表中可以同时给出参数的类型和名称,也可以只给出参数的类型,省略参数的名称
//注意()的优先级高于*,第一个括号不能省略,如果写作returnType *pointerName(param list);就成了函数原型,它表示函数的返回值类型为returnType*
int max(int a, int b){
	return a>b?a:b;
}
void main(){
	int maxVal;
	int x=10;
	int y=20
	//函数指针
	//这里相当于将一个函数的首地址赋值给了一个指针变量
	int (*pMax)(int, int)=max;
	//通过函数指针调用
	maxVal=(*pMax)(x, y);
	maxVal=pMax(x,y)
}

在这里插入图片描述
(6)回调函数
1)基本介绍
a.函数指针变量可以作为某个函数的参数来使用,回调函数就是通过函数指针调用的函数
b.简单的讲:回调函数是由别人的函数执行调用你传入的函数
注:函数中通过指针调用其他函数

动态内存分配

(1)C语言的内存分配说明

  1. 全局变量–内存中的静态存储区
  2. 非静态的局部变量–内存中的动态存储区–stack栈
  3. 临时使用的数据–建立动态内存分配区域,需要时随时开辟,不需要及时释放–heap堆
  4. 根据需要向系统申请所需要的空间,由于未在声明部分定义其所需大小的空间或者数组,不能通过变量名或则数组名来引用这些数据,只能通过指针来引用

(2)内存动态分配的相关函数

1.头文件#include<stdlib.h>声明了四个关于内存动态分配的函数
2.函数原型void *malloc(usigned int size)
a.作用–在内存中的动态存储区分配一个长度为size的连续空间
b.形参的size的类型为无符号整型,函数返回值时所分配区域的第一个字节的地址。
3.函数原型void *calloc(unsigned n, unsigned size)
a.作用–在内存的动态存储区中分配n个长度为size的连续空间,这个空间一般较大,足以保存一个数组
b.用calloc函数可以为一维数组开辟动态存储空间,n为数组元素的个数,每个元素长度为size
c.函数返回指向所分配域的起始位置的指针;分配不成功,返回NULL
4)圆形函数:void free(void *p)
a.作用–释放变量p所指向的动态空间,使这部分空间能重新被其他变量使用
b.free函数无返回值
5)函数原型void *realloc(void *p, unsigned int size)
a.作用–重新分配malloc或calloc函数获取的动态空间大小,将p指向的动态空间大小改变为size,p值不变,分配失败返回NULL
注:
void *类型,这种指针称为无类型指针,即不指向哪一种具体的数据类型,只表示用来指向一个抽象的类型的数据,即仅提供一个纯地址,而不指向任何具体的对象

(3)动态内存分配的基本原则

  1. 避免分配大量的小内存块,分配堆上的内存有一些系统开销,所以分配许多小的内存卡比分配几个大的内存块的系统开销大
  2. 仅在需要时分配内存,只要使用完堆上的内存块,就释放它,否则可能出现内存泄漏
  3. 总是确保释放已分配的内存。在编写分配内存的代码时,要确定在打吗的什么地方释放内存
  4. 在释放内存之前,确保不会无意中覆盖上已分配的内存地址,否则程序就会出现内存泄漏。在循环中分配内存时,要特别小心
结构体

面向对象的思维
(1)结构体域结构体变量的区别和联系
a.结构体是自定义的数据类型,表示的是一种数据类型
b.结构体变量代表一个具体变量
c.结构体类似于类,结构体类似于实例对象
(2)结构体的声明

struct 结构体名称{
	成员列表;
}
//结构体名称首字母大写
//结构体成员/包含的变量,一般是基本数据类型、也可以是数组、指针、结构体等

注:
1)成员声明和变量相同
2)字段的类型可以是:基本类型、数组、指针、结构体等
3)在创建一个结构体变量后,需要给成员赋值,如果没有赋值就使用可能导致程序异常终止
4)不同结构体变量的成员是独立的,互不影响,一个结构体变量的成员更改,不影响另外一个

共用体

(1)基本介绍

  1. 共用体属于构造类型,它可以包含多个类型不同的成员。和结构体非常类似,但是也有不同的地方
  2. 公用体有时也被称为联合或者联合体,定义格式为: union 共用体名{成员列表}
  3. 结构体和共用体的区别:结构体的各个成员变量会占用不同的内存,互相之间没有影响;而共用体的所有成员变量占用同一段内存,修改一个成员变量会影响其余所有成员
//定义方式1
union {
	int a;
	char b;
} test;
//定义方式2
union TEST{
	int a;
	char b;
}
union Test test;

//当a被赋值时,char的值也将同时被赋值

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值