1.review二维数组
二维数组的本质,也是一维数组,只不过,一维数组中的每个元素,又是一个一维数组而己。
声明/定义
int[4] array[3] => int array[3][4];
二维数组的逻辑形式
二维数组的存储形式
2.指针常量变量指向空指针
十六进制
指针的指向
#include <stdio.h>
int main(int argc, char *argv[])
{
int a;
int *p = &a;
printf("%p\n",p);
*p = 100;
printf("%d\n",a);
int b;
p = &b;
*p = 231;
printf("%d\n",b);
return 0;
}
野指针
一个指针变量,如果,指向一段无效的空间,则该指针称为野指针,是由invalidpointer翻译过来,直译是无效指针。
常见情型有两种,一种是未初化的指针,一种是指向一种己经被释放的空间。
对野指针的读或写崩溃尚可忍受,对野指针的写入成功,造成的后果是不可估量的。
对野指针的读写操作,是危险而且是没有意义的。
世上十之八九最难调的bug皆跟它有关系。
NULL指针(零值无类型指针)
如何避免野指针呢。
NULL是一个宏,俗称空指针,他等价于指针(void*) 0
。(void*)0
是一个很特别的指针,因为他是一个计算机黑洞,既读不出东西,也不写进东西去。
所以被赋值NULL的指针变量,进行读写操作,是不会有内存数据损坏的。
c标准中是这样定义的:
define NULL ((void *)0)
故常用NULL来给临时不需要初初始化的指针变量来进行初始化。
或对己经被释放指向内存空间的指针赋值。
可以理解为c专门拿出了NULL(零值无类型指针),用于作标志位使用。
void本质
void即无类型,可以赋给任意类型的指针,本质即代表内存的最小单位
,在32位机上地位等同于char。
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("sizeof(char) = %d\n",sizeof (char));
printf("sizeof(void) = %d\n",sizeof (void));
return 0;
}
声明两个变量分别表示什么
int *p,q;
#include <stdio.h>
int main(int argc, char *argv[])
{
char *p,q;
printf("sizeof(*p) = %d\n",sizeof (p));
printf("sizeof(q) = %d\n",sizeof (q));
return 0;
}
区别指针
int *ptr_var;
ptr_var,&ptr_var,*ptr_var的三者区别
ptr_var:指针变量
&ptr_var:指针变量的地址
*ptr_var:取指针变量地址的内容
3.指针的运算
指针运算的本质是指针中存储的地址的运算。
指针可参与的运算。
赋值运算
区别初始化和赋值。
不兼容类型赋值会发生类型丢失。
为了避免隐式转化带来可能出现的错误,最好用强制转化显示的区别。
指针的算术运算,不是简单的数值运算,而是一种数值加类型运算。将指针加上或者减去某个整数值(以n*sizeof(T)
为单位进行操作的)。
运算符 | + |
- |
++ |
-- |
---|---|---|---|---|
示例 | p+3 |
p-3 |
p++/++p |
p--/--p |
#include <stdio.h>
//指针类型(步长)+地址(物理数据)
//数值+1,就是加1。
//指针+1,加的是步长,指针类型的大小
int main(int argc, char *argv[])
{
int *p = (int*)0x0001;
int data= 0x0001;
printf("p =%#x p+1 =%#x\n",p,p+1);
printf("p =%#x p+1 =%#x\n",data,data+1);
printf( "(double*)p = %#x(double*)p+1 = %#x\n" ,(double*)p,(double*)p+1);
printf("(int)p = %#x(int)p+1 = %#x\n" ,(int)p,(int)p+1);
printf( "%x\n" ,++p);
printf( "%x\n" ,++data);
int arr[10];
int *pHead = &arr[0];
int *pTail = &arr[9];
printf("%d \n" ,pHead);
printf("%d \n" ,pTail);
printf("%d \n" ,pHead - pTail);
int arr1[10];
int *pHead1 = (int)&arr1[0];
int *pTail1 = (int)&arr1[9];
printf("%d \n" ,pHead1 - pTail1);
return 0;
}
4.指针运算续加数组遇上指针
#include <stdio.h>
//指针类型(步长)+地址(物理数据)
//数值+1,就是加1。
//指针+1,加的是步长,指针类型的大小
int main(int argc, char *argv[])
{
int *p=0x0001;
int *q=0x0005;
if(p+1 == q)
{
printf("p+1 == q\n");
}
return 0;
}
注意:只有当指针指向一串
连续的存储单元
时,指针的移动才有意义。才可以将一个指针变量与一个整数n做加减运算
练习:判断是否是回文字符串
#include <stdio.h>
//指针类型(步长)+地址(物理数据)
//数值+1,就是加1。
//指针+1,加的是步长,指针类型的大小
int main(int argc, char *argv[])
{
char name[5] = {
'm','a','d','a','m'};
char *ph = &name[0];
char *pt = &name[4];
int flag = 1;
while(ph<pt)
{
if(*ph == *pt)
{
ph++;
pt--;
}
else {
break;
flag = 0;
}
}
if(flag ==1)
{
printf("回文");
}else {
printf("非回文");
}
return 0;
}
指针的运算只能发生在同类型或整型之间,否则会报错或是警告。
指针的运算,除了数值以外,还有类型在里面。
数组遇上指针
一维数组的访问方式
传统方式(下标/偏移法)
数组名是数组的唯一标识符,数组名代表数组首元素的地址
。
我们可以用下标
的方式对数组进行访问。
除此之外,还可以用,本质方法
进行访问。
数组名是常量指针
数组名是常量,才可以唯一的确定数组元素的起始地址。
一维数组名跟一级指针的关系
数组除了可以用下标法和本质法访问以外,还可以用指针法访问。能用数组名解决的问题的,都可以用指针来解决,而能用指针来解决的问题,并一定能用数组名来解决。
#include <stdio.h>
//数组访问 偏移法 本质法
int main(int argc, char *argv[])
{
int arr[10] = {
1,2,3,4,5,6,7,8,9,0};
for (int i=0;i<10;i++)
{
printf("%d\n",*(arr+i));
}
return 0;
}
#include <stdio.h>
//数组访问 下标法
int main(int argc, char *argv[])
{
int arr[10] = {
1,2,3,4,5,6,7,8,9,0};
for (int i=0;i<10;i++)
{
printf("%d\n",arr[i]);
}
return 0;
}
#include <stdio.h>
//数组访问 下标法
//一维的数组名,可以赋给一级指针。
//数组名能干的,指针就能干,数组不能干的,指针也能干。
int main(int argc, char *argv[])
{
int arr[10] = {
1,2,3,4,5,6,7,8,9,0};
int *pa = arr;
for (int i=0;i<10;i++) {
printf("%d\n",*pa);
pa++;
}
return 0;
}
5.二维数组与指针
#include <stdio.h>
//数组访问 下标法
//一维的数组名,可以赋给一级指针。
//数组名能干的,指针就能干,数组不能干的,指针也能干。
int main(int argc, char *argv[])
{
int arr[10] = {
5,5,5,5,5,5,5,5,5,5};
int *pa = arr;
for (int i=0;i<10;i++) {
printf("%d\n",(*pa)++);
//printf("%d\n",arr[0]++);
}
for (int i=0;i<10;i++) {
printf("%d\n",*(pa+i));
}
return 0;
}
1.数组名是一个常量,不允许重新赋值。⒉指针变量是一个变量,可以重新赋值。
3.p+和ai均表示数组元素ai的地址,均指向a利
4.*(p+i)和*(ati)均表示p+i和a+i所指对象的内容a0。
5.*p++︰等价于"(p++)。其作用:先得到*p,再使p=p+1。
6.(*p)++:表示将p所指向的变置(元素)的值加1。即等价于a[i]+。
7.指向数组元素的指针也可以表示成数组的形式,即允许指针变量带下标,如*(p+i)可以表示成p。
二维数组的访问方式
下标法
数组元素的表示方法是:数组名称[行][列]
,对于m行n列的二维数组,a[0][0]
是数组的第一个元素,a[m-1][n-1]
是最后一个元素。
本质偏移法
从a
到a[0]
到a[0][0]
都经历了什么?
#include <stdio.h>
//数组访问 下标法
//一维的数组名,可以赋给一级指针。
//数组名能干的,指针就能干,数组不能干的,指针也能干。
int main(int argc, char *argv[])
{
int arr[3][4] = {
1,2,3,4,10,20,30,40,111,222,333,444};
for(int i=2; i>=0; i--){
for(int j=3; j>=0; j--){
printf("a[%d][%d] = %#x\n",i,j,&arr[i][j]);
}
printf("=========== \n");
}
printf( "arr = %#p arr+1 = %#x arr+2 = %#x \n", arr, arr+1,arr+2);
return 0;
}
#include <stdio.h>
//数组访问 下标法
//一维的数组名,可以赋给一级指针。
//数组名能干的,指针就能干,数组不能干的,指针也能干。
int main(int argc, char *argv[])
{
int arr[3][4] = {
1,2,3,4,10,20,30,40,111,222,333,444};
for(int i=2; i>=0; i--){
for(int j=3; j>=0; j--){
printf("a[%d][%d] = %#x\n",i,j,&arr[i][j]);
}
printf("=========== \n");
}
printf( "arr = %#p arr+1 = %#x arr+2 = %#x \n", arr, arr+1,arr+2);
printf( "arr[0] = %#p arr[0]+1 = %#x arr[0]+2 = %#x \n", arr[0], arr[0]+1,arr[0]+2);
return 0;
}
二维数组名,跟二级指针,没有关系
二维数组名的本质是,数组指针
6.函数之库函数rand_srand
c语言包含两部分,c语法和c标准库。
使用函数,可以有如下好处:
可以提高程序开发的效率。
提高了代码的重用性。
使程序变得更简短而清晰。
有利于程序维护。
库是对函数的再一次升级
库存在的意义
将常用的函数分类组织到一起,即可制作成函数库。
库存在的意义,就是避免重复造轮子。
像我们使用的printf 函数,没有必要每个使用此功能的函数,都要重写来实现。重复现成的、可用的、已经证明很好用的东西就是造轮子。
如何使用库函数
由C语言系统提供;用户无须定义,也不必在程序中作类型说明;只需在程序前包含有该函数定义的头文件(/usr/include/stdio.h),而不无关系库在哪里(/usr/lib/libc.so 标准库);
到底提供了哪些函数可以通过查表的方式获得。
函数的三要素,函数名,函数参数,函数返回值
,却是我们要研究的。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(int argc, char *argv[])
{
unsigned int seconds = time(NULL);
printf("%d\n",seconds);
return 0;
}
随机函数rand():
使用随机函数产生,某一范围内了随机数。比如生成[1,100]以内的随机数。
srand和 rand()配合使用产生伪随机数序列。
rand函数在产生随机数前,需要系统提供的生成伪随机数序列的种子,rand根据这个种子的值产生一系列随机数。
如果系统提供的种子没有变化,每次调用rand函数生成的伪随机数序列都是一样的。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(int argc, char *argv[])
{
srand(time(NULL)); //给随机数发生器一个种子,rand去发生器去取数
int randNum = rand();
printf("%d\n",randNum);
randNum = rand();
printf("%d\n",randNum);
randNum = rand();
printf("%d\n",randNum);
randNum = rand();
printf("%d\n",randNum);
randNum = rand();
printf("%d\n",randNum);
return 0;
}
练习:产生10个不同的随机数int randArr[10]