嵌入式入门学习笔记,遇到的问题以及心得体会!
DAY6
笔记:
‘&’ :取址运算符
‘*’ :取值运算符
总结:
指针变量只能用来存地址
可以通过指针变量间接访问(查看/修改)所指向空间的内容
eg:
int a = 100;
int *p = &a;
int b = 80;
&a++;//error
p++;//OK
&a = &b;//error
p = &a;
p = &b;//OK
eg:
int a = 90;
char ch = ‘K’;
int *p = &a; //p一次性访问空间为4字节
p = &ch; //赋值时注意左右两边类型要一致
char *p = &ch; //p一次性访问空间为1字节
练习:实现二维字符数组中多个字符串的排序(5个字符串)
一,二级指针:存储一级指针地址的变量
指针的指针:
(定义意味着有空间
有空间就意味着地址)
如何定义一个一级指针?
存储类型 数据类型 * 指针变量名 ;
如何定义一个二级指针:
存储类型 数据类型 * * 指针变量名;
分析:
存储类型:该二级指针自身的存储类型
数据类型 *:该二级指针所指向的类型
数据类型 ** :该二级指针自身的类型
指针变量名:该二级指针在内存空间中的名字
总结:
(1)如何确定指针变量自身的数据类型?
—》直接去掉【指针变量名】,剩余的均是该指针自身的类型
eg:
int *p; p的类型—》int *
int **pp; p的类型—》int **
char *pp; p的类型—》char **
(2)如何确定指针所指向的数据类型?
----》直接去掉【 指针变量名】,剩余的均是该指针所指向的类型
eg:
int *p ; p所指向的类型是:int
char **pp; pp所指向的类型:char *
(3)如何确定指针一次性访问空间的大小?
----》由指针所指向的类型来决定
eg:
int *p; //p一次性访问空间为4字节
char **pp; //p一次性访问空间为4字节
指针在32OS下占多少个字节?
解释:在32OS下,指针永远占4个字节,因为32OS下内存空间总共为4G这么大,
想要把这4G大的空间用编号表示完全即(0 ~ 4G-1)—>( 0 ~ 2^32-1)
则:可以用32个二进制数字就可以表示完全,32bit == 4bytes
(基于32位操作系统下来说的)
空指针和野指针:
空指针:
值为0的指针,但是值为0的指针用宏定义将其宏定义为NULL
对于值为0的这个字节空间来说,只能被当做初始化来使用,不能访问(查看/修改)其空间里面的值
如果不小心访问了这片空间则会出现段错误
注意:零号地址是禁止被访问的!!
野指针:
指向不明确的指针,杜绝野指针的出现,可以先将其赋值为空指针
总结:
对于空指针:既不能查看,也不能修改
对于野指针:不能修改,但可以查看
出现段错误的原因:
(1)访问了不该访问的空间
(2)越界
(3)修改常量区的内容
二、指针与一维数组:
指针的算术运算: + - * / % ++ –
假设有一个指针变量叫p和q(p和q是同种类型的指针变量):
p + N :代表p向地址增大的方向移动N个数据类型的大小:p + N = p + sizeof(int) *N
p - N :代表p向地址减小的方向移动N个数据类型的大小:p - N = p - sizeof(int) *N
p++: 代表p向地址增大的方向移动一个数据类型的大小:p++ = p + sizeof(int)*1
p–: 代表p向地址减小的方向移动一个数据类型的大小:p-- = p - sizeof(int)*1
p - q :(必须得是同类型之间的指针进行相减)
代表两个指针变量之间相隔数据元素的个数:p-q = (p-q)/sizeof(数据类型)
总结:p++ 和 p+1有什么区别?
p++会引起指针的指向发生改变—》p++ <==> p = p+1;
p+1不会引起指针的指向发生改变
数组名:
(1)能够代表整个数组—》sizeof(数组名) —》可以测得整个数组所占字节空间的大小
(2)代表数组首元素的地址(起始地址/首地址)
打印数组元素的方式:
arr[i] <> *(arr+i) <> *(p+i) <> *(p++) <> p[i] <> i[arr] <> i[p]
注意:数组名是一个地址常量,因此不能进行自加或者自减的运算
#include <stdio.h>
int main(int argc, const char *argv[])
{
int arr[5] = {1,2,3,4,5};
//定义一个指针指向该一维数组中的首元素
int *p = arr;
printf("sizeof(arr) = %d\n",sizeof(arr));
printf("arr = %p\t&arr[0] = %p\n",arr,&arr[0]);
int i;
for(i = 0;i<5;i++)
{
//printf("%d ",arr[i]);
//printf("%d ",*(arr+i));
//printf("%d ",*(arr++));
//printf("%d ",*(p+i));
//printf("%d ",*(p++));
//printf("%d ",p[i]);
//printf("%d ",i[arr]);
printf("%d ",i[p]);
}
printf("\n");
return 0;
}
因此:
在算术运算中:地址常量只是不能进行自加和自减的运算,而指针变量均符合该算术运算,
因此不能对数组名进行自加和自减!!!
练习:
1,计算一个字符串中空格的个数(利用指针实现)
2,将整形一维数组的冒泡排序更改为指针的方式(1,不改变指向,2,改变指向)
改变指向如下:
#include <stdio.h>
#define M 5
int main(int argc, const char *argv[])
{
//定义一个数组
int arr[M] = {0};
//定义一个指针指向该数组
//int *p = &arr[0];
int *p = arr;
//完成赋值
int i,j;
for(i=0;i<M;i++)
{
//scanf("%d",&arr[i]);
scanf("%d",p+i);
}
//输出元素
for(i=0;i<M;i++)
{
//printf("%d ",arr[i]);
printf("%d ",*(p+i));
}
printf("\n");
printf("冒泡中...\n");
//控制趟数
for(i=0;i<M-1;i++)
{
p = arr;
//控制每一趟的次数
for(j=0;j<M-1-i;j++)
{
if(*p > *(p+1))
{
int Temp;
Temp = *p;
*p = *(p+1);
*(p+1) = Temp;
}
p++;
}
}
p = arr;
printf("冒泡之后:\n");
for(i=0;i<M;i++)
{
printf("%d ",*(p+i));
}
putchar('\n');
return 0;
}
不改变指向如下:
#include <stdio.h>
#define M 5
int main(int argc, const char *argv[])
{
//定义一个数组
int arr[M] = {0};
//定义一个指针指向该数组
//int *p = &arr[0];
int *p = arr;
//完成赋值
int i,j;
for(i=0;i<M;i++)
{
//scanf("%d",&arr[i]);
scanf("%d",arr+i);
}
//输出元素
for(i=0;i<M;i++)
{
//printf("%d ",arr[i]);
printf("%d ",*(arr+i));
}
printf("\n");
printf("冒泡中...\n");
//控制趟数
for(i=0;i<M-1;i++)
{
//控制每一趟的次数
for(j=0;j<M-1-i;j++)
{
if(*(arr+j) > *(arr+j+1))
{
int Temp;
Temp = *(arr+j);
*(arr+j) = *(arr+j+1);
*(arr+j+1) = Temp;
}
}
}
printf("冒泡之后:\n");
for(i=0;i<M;i++)
{
printf("%d ",*(arr+i));
}
putchar('\n');
return 0;
}
三、指针与二维数组:
作业:
1,实现二维字符数组中多个字符串的排序(5个字符串)—》用数组方式
#include <stdio.h>
#include <string.h>
#define M 5
#define N 20
int main(int argc, const char *argv[])
{
//实现5个字符串的排序输出
char str[M][N] = {'\0'};
printf("请输入:\n");
int i,j;
for(i=0;i<M;i++)
{
scanf("%s",str[i]);
}
printf("输出为:\n");
for(i=0;i<M;i++)
{
printf("%s\n",str[i]);
}
printf("冒泡中:.....\n");
for(i=0;i<M-1;i++)
{
for(j=0;j<M-1-i;j++)
{
if(strcmp(str[j],str[j+1]) > 0)
{
//交换
char Temp[N] = {'\0'};
strcpy(Temp,str[j]);
strcpy(str[j],str[j+1]);
strcpy(str[j+1],Temp);
}
}
}
printf("排序之后:\n");
for(i=0;i<M;i++)
{
puts(str[i]);
}
return 0;
}
2,利用指针实现strcat和strcpy
strcat:
#include <stdio.h>
#define M 20
#define N 10
int main(int argc, const char *argv[])
{
//利用指针实现strcat的功能
char str1[M] = {'\0'};
char str2[N] = {'\0'};
char *pStr1 = str1;
char *pStr2 = str2;
printf("请输入:\n");
gets(pStr1);
gets(pStr2);
printf("连接之前:str1 = %s\n",pStr1);
//遍历str1这个字符串至末尾第一个'\0'处
while(*pStr1)
{
pStr1++;
}
//再遍历str2这个字符串,并将每一个有效字符连接在str1的后面
while(*pStr2)
{
*pStr1++ = *pStr2++;
}
pStr1 = str1;
printf("连接之后:str1 = %s\n",pStr1);
return 0;
}
3,利用指针将一个字符串进行翻转:“break” <–>“kaerb”
#include <stdio.h>
#include <string.h>
#define M 20
int main(int argc, const char *argv[])
{
//实现字符串的倒置
char str[M] = {'\0'};
char *p = str;
char *q = p;//指针变量之间可以相互赋值
gets(p);
//第一种:让q指向末尾最后一个有效字符
//q = q + strlen(str) - 1;
//第二种:让q指向最后一个有效字符
while(*q)
{
q++;
}
q--;
while(p < q)
{
//交换
char Temp;
Temp = *p;
*p = *q;
*q = Temp;
p++;
q--;
}
p = str;
printf("倒置之后的结果为: %s\n",p);
return 0;
}