从纯小白的角度入手,重新开始记录指针的学习。主干,练习,补充。
一.内存和地址
内存中的每个位置总包含一些值,每个字节通过地址来标识,如下:
100 | 101 | 102 | 103 | 104 | 105 |
每个位置为1字节(byte),在许多机器上,1byte=8bit,即一个位置包含8个位。每个字只有一个地址,一般为最左边那个字节的位置。我们常把更多字节合在一起作为一个更大的内存单位,如下两个字的存储空间:
100 | 104 |
Q:对于不同数据类型在内存中存储的结构图是怎么样的呢?
二.指针变量理解
指针变量用于存放其他变量的地址。
1.声明
指针变量a的值为另一变量b的地址,a的类型为b的类型。如:int *a;表示a是一个指向int类型变量的指针变量。声明一个指针变量不会自动分配任何内存。
2.初始化
在对指针执行间接访问前,指针初始化,或指向现有的内存,或分配动态内存。
a.指向某变量地址。如:int b; int*a=&b;
b.初始化为NULL指针
作为一个特殊指针变量,声明*a=NULL表示a目前不指向任何有效内存地址,指向内存地址为0的地方。与*a=0是等价的。在使用前需用malloc动态分配获得内存。(动态内存是之后学习的又一章节)Q:NULL指针的应用?
int *a = NULL; // 声明一个指向整型变量的指针并初始化为NULL
a = (int *)malloc(sizeof(int)); // 分配一个整型变量大小的内存空间给指针a
if (a != NULL) {
*a = 10; // 在分配内存后,可以通过指针a来操作对应的内存空间
}
// 使用完指针a后,记得释放内存
free(a);
二者殊途同归,本质上是为了使指针指向明确的、一定大小的存储空间。
三.含指针变量的表达式
1.*的用途
在声明时*用来指明该变量为指针变量,之后使用时*用于间接访问指针变量指向的地址中存储的内容。如声明int *a;之后初始化a=&b;则*a与b的值相同,再*a=5则b=5。
ps:强制类型转换
*(int*)100=25;
表示:把100从整型转换为指向整形的指针,再利用*间接访问,把25存进地址为100位置处 。
2.指针变量作为左值、右值进行访问的区别
3.指针运算
(1)算术运算
a.指针+/-整数
标准定义这种形式只可用于指向数组中某个元素的指针,且结果类型也是指针。+1即指针指向数组中下一个元素。
ps:这里需要结合内存理解,不同类型的变量在内存空间中占据的字节数有所不同,而指针变量的值就是地址,故对于指针变量做加减,如果只像一般的算术运算,比如+1就是下一个字节,一个int类型数据占据的内存都不止1个字节,指针不就指向int值内部的某个字节了?
当然,计算机设计者不会让这种麻烦产生啦QAQ!当指针和整数量执行运算时,会根据指针指向类型的大小运算。如:某机器上float占4个字节,声明float*a=&b;已知a=&b=100,a+3实质上得到的新地址为112。即增加的是3个float的大小,而非3个字节。这里小小补充一下:
我们会常用到字符串定义:char*a和char a[]是等价的(ps:前者需要malloc分配内存,后者需要表明数组大小)在前者定义下,可以用下标,如a[0]
该形式亦适用于malloc分配的内存。(目前还没有遇到应用)
b.指针-指针
只适用于当两个指针都指向同一个数组中的元素时,结果类型为有符号整数类型。减法运算的值为两个指针在内存中的距离(以数组元素的长度为单位,而非字节),如:p1=&a[i],p2=&a[j],则p2-p1=j-i。
(2)关系运算
前提是两个指针都指向同一个数组中的元素,使用<,>,<=,>=等关系运算用于判断它们在数组中的相对位置。目前看到的应用就是在for循环的条件表达式中,以位置关系真假作为一个限制条件。
四.基础编程练习
不运用C中的操纵字符串的函数库编写函数
1.查找匹配的第一个字符
查找source字符串中匹配chars字符串中任何字符的第一个字符,然后返回一个指向source中第一个匹配所找到位置的指针。函数原型:char*fin_char(char const*source,char const*chars)。
若所有字符均不匹配,函数返回NULL;若任一参数为NULL或所指向的字符串为空,函数也返回NULL。参数所指向的字符串不会被修改(const用法见文件)
#include<stdio.h>
char* find_char(char const* source, char const* chars);
int main()
{
char a[100], b[100],* result;
printf("source:");
scanf_s("%s", a,sizeof(a));
printf("chars:");
scanf_s("%s", b,sizeof(b));
result = find_char(a, b);
printf("%c\n",*result);
printf("%p\n",result);
return 0;
}
char* find_char(char const* source, char const* chars)
{
char const* p=source;
char const* q = chars;
if (source == NULL || chars == NULL)
return NULL;
else
while (*p!='\0')
{
q = chars;
while (*q!= '\0')
{
if (*p == *q)
return (char*)p;
q++;
}
p++;
}
return NULL;
}
2. 删除一个字符串的一部分
函数原型:int del_substr(char*str,char const*substr)
需要先判断substr是否出现在str中,若是函数返回1,否则返回0;若出现,函数应把str中位于该子串后面的所有字符复制到该子串的位置,从而删去这个子串,然后函数返回1。若substr在str中出现了多次,函数只删除第一个substr。(写的时候分开了)
#include<stdio.h>
//统计字符串长度--对应于strlen(s)函数
int strlength(char const* str)
{
int len = 0;
while (*str++ != '\0')
len++;
return len;
}
//寻找字符串--strncmp(a,b,len)
int strfind(char* str1, char const* str2)
{
int len = strlength(str2);
for (int i = 0; i < len; i++) {
if (str1[i] != str2[i])
return 0;
}
return 1;
}
//删除字符串--C中无可以直接删除子串的函数,但可利用strcpy复制
void del_substr(char* str, char const* substr)
{
int strlen = strlength(str);
int sublen = strlength(substr);
char* ptr = str;
char* tmp = str;
int flag = 1;
while (*ptr)
{
if (flag&&strfind(ptr, substr))
{
ptr += sublen;
flag = 0;
}
else
{
*tmp = *ptr;
tmp++;
ptr++;
}
}
*tmp = '\0';
}
int main()
{
char str[100], sub[100];
printf("str:");
scanf("%s", str);
printf("sub:");
scanf("%s", sub);
del_substr(str, sub);
printf("Result:%s\n", str);
return 0;
}
扣几张之前朋友的小组笔记总结(翁恺指针视频)
在阅读关系运算时发现一个有趣的小知识:
C语言--输入任意一个数,判断它的奇偶性(三种方法)_有以下程序段,,要求先输入一个整数,然后再判断是奇数还是偶数: s=①(input("请输-CSDN博客
ps:《C和指针》