C语言-------第四次笔记

指针

指针的定义
指针的类型
指针的指向内容
指针的运算
数组与指针
指针与函数
动态分配内存 结构体 文件读写 头文件与实现文件实例之计算器 文件操作训练之字符串查找
指针的定义
  • 指针是一个变量
  • 指针只能存地址
  • 指针占据8个字节空间
int main(){ int *a; char printf("a的大小:%d\n", sizeof(a)); printf("a的地址:%p\n",a); printfC'XdXn", sizeof(b)); }输出:a的大小:8a 的地址:0000000000000001

指针的声明
int *p;
char *p;
int *arr[5];
int **p;
  • 指针的声明相对于普通变量的声明多了一个一元运算符、”。
  • 运算符”是间接寻址或者间接引用运算符。当它作用于指针时,将访问指针 所指向的对象。
  • P是一个指针,保存着一个地址,该地址指向内存中的一个变量;下则会访问 这个地址所指向的变量。
  • 声明一个指针变量并不会自动分配任何内存。
  • 在对指针进行间接访问之前,指针必须进行初始化:或是使他指向现有的内 存,或者给他动态分配内存,否则这个指针会变成野指针。
指针初始化
int a = 5; int *p = &a;

  • " * "定义的时候表明是一个指针变量,使用的时候表示取地址的值
  • " & "取某一个变量地
int *p; p = (int *)malloc(sizeof(int) * 10) free(p);

  • 指针的初始化实际上就是给指针一个合法的地址,让程序能够清楚地知道指针的指向,而 不至于变为野指针
指针的类型
  • 判断指针类型的方法:去掉星号*和变量名就是指针的类型
  • 【C语言-------第四次笔记】P 与 * 结合,所以说明P是一个指针,然后再与int结合,说明指针所指向的内容的类型为 int 型.
  • int p[3]
    P与[]结合.说明P是一个数组,然后与int结合,说明数组里的元素是整型的.
  • int *p[3];
    P与[ ]结合因为其优先级比" * "高,所以 P 先是一个数组,然后再与” * ”结合。说明数组里的元素 是指针类型,然后再与int结合,说明指针所指向的内容的类型是整型的.
  • int(*p)[3];
    P 与 * 结合.说明 P 是一个指针然后再与[ ]结合 (与 ”()” 这步可以忽略,只是为了改变优先级),说明指针所指向的内容是一个数组,然后再与int结合,说明数组里的元素是整型的.
  • int **p;
    P 与 ** 结合,说是 *P 是一个指针,然后再与 * 结合,说明指针所指向的元素是指针,然后再与 int 结合,说明该指针所指向的元素是整型数据.
  • int p(int)
    P 与 () 结合.说明 P 是一个函数,然后进入 () 里分析,说明该函数有一个整型变量的参数, 然后再与外面的int结合.说明函数的返回值是一个整型数据.
  • int (*p)(int);
    P 与指针结合,说明 P 是一个指针,然后与 () 结合,说明指针指向的是一个函数.然后再与 () 里的 int 结合,说明函数有一个int 型的参数,再与最外层的 int结合,说明函数的返 回类型是整型.
指针的指向内容
  • 指针存储的内容为变量的地址,也就是说指针的是一个指向作用,指向变量所存储的内容
int main(){ int a = 5; int *p = &a; return 0; }

指针的运算
  • 指针+(-)整数
    可以对指针变量P进行P++、p--、p + i 等操作,所得錯果也是一个指针,只是指 针所指向的内存地址相比于p所指的内存地址前逬或者后退了 i (对应指针指向类 型对应大小)个操作数。
int main()(char a = *1'; char *p - &a; printf("p:%p\n",p); P++;prirrtf("p++之后始果:%p\n",p); P—;printf("p--之后塔果:Xp\n",p); 叶5; printf("p+5之后结果:%p\n"/p); return 0; } 输出: p:000000000062FE17 p++之后结果:0e000e0eee62FEi8 p--之后结果:0e0000000e62FE17 P+5之后结果:0000G0000062FE1C

P是一个char类型的指针,指向内存地址0062FE17处。则 p++ 将指向与 p 相邻的下一 个内存地址,由于 int 型数据占4个字节,因此 p++ 所指的内存地址为1000000b。其余类推,不过要注意的是,这种运算并不会改变指针变量 p 自身的地址,只是改变了它所 指向的地址.
**********************************************************************************8
数组与指针
  • 数组的数组名其实可以看作一个指针,因为数组名是指向数组的第一个元素,上面 num数组指向的也就是第一个元素1,数组名本身是没有占有内存的
int array[10]={0,l,2,3?^,5,6,7,8,9},value; value-array[0]; value=https://www.it610.com/article/array[3]; value=array[4];

另外一种解释是将数组名指向数组的第0个单元,那么(array+n)也就是一个指向数组 里的第n个单元的指针
P 指向的是数组的首地址,也就是数组的第一个元素,那么 P++ 之后也就是对指针 P 前进了 4(int类型)个操作数,而数组是分配了连续空间,所以相对地址是加减也就是数组元素 的位置变换
指针数组
  • 指针数组.是一个数组,数组中的每一个元素都是指针
    对于上面的定义和初始化,data是指针数组的名字,也就是指向指针数组首元素的指 针.(指针的指
    针).data[i]是data这一个数组的第i个元素,也就是一个指向int的指针 指针可以当成数组来使用。
数组指针
  • 数组指针,是一个指针,它指向一个数组
    数组作为参数传入函数的时候,对于被调用的函数参数就是指针
指针与函数
  • 函数指针是指向函数的指针变量
  • 通常我们说的指针变量是指向一个整型、字符型或数组等变量,而函数指针是指向函数
  • 函数指针可以像一般函数一样,用于调用函数、传递参数,函数指针声明
  • 函数指针变量可以作为某个函数的参数来使用的,回调函数就是一个通过函数指针调用的 函数。也就是
    说回调函数是由别人的函数执行时调用你实现的函数。
动态分配内存
  • 为什么需要动态分配内存:
    1.存储的数据 需要延长生命周期
    2.一个指针变量需要存储数据,变量本身只能存地址
    不能存数据,需要分配内存空间来存储数据
#include #include int main(){ //char name[100] = {}; //如果使用指针变量接收数据 //必须先为这个指针变量分配一片指向的内存空间 //有内存空间 才能存数据 //导入头文件stdlib.h //使用malloc (memory alloc)申请内存空间 char *name ; name = (char *)malloc(10*sizeof(char)); if(name == NULL){ // 申请内存失败 exit(EXIT_FAILURE); } scanf("%s", name); printf("%s\n",name); //使用realloc动态改变已经分配内存的大小 //增加或者减少 name = (char *)realloc(name, 20*sizeof(char)); if(name == NULL){ //退出之前必须将之前分配的内存释放掉 free(name); exit(EXIT_FAILURE); }//使用完毕必须自己手动释放内存 free(name); return 0; }

结构体
  • 为什么要使用结构体
    int , float 只能存单个数据
    int num[] 可存储多个数据 但必须同种类型
    需要一种类型 可以保存多种数据
  • 结构体是什么
    int char
    一种结构体
  • 如何定义结构体类型
    注意定义结构体类型时 内部类型不能赋初值
struct student{};

  • 结构体内存计算方式
    对齐方式 小类型 -》大类型对齐
  • 指针使用->访问元素
    p->
#include int main(){ struct person { int age; float height; }; return 0 ; }

文件读写
// 创建文件 #include int main (){ FILE*fp =fopen( "C:\\Users\\33573\\Desktop\\test.txt","a+"); //r:只能读;w:只能写且要覆盖前面的内容;a:可写可读 return 0; }//打开文件 // 写入内容 fputc fgetc fputc('a',fp); fgetc(fp); // 重新定位文件指针的位置 fseek(fp,3,SEEK_SET); //SEEK_SET;SEEK_SET; SEEK_END fputs("hello world",fp); // 按照一定格式写入内容 int num[5] = {1,2,3,5,5}; fwrite( num,sizeof(num),1,fp); //写入的是二进制,视频,音频 结构体 // 读取内容 fdeto(fp); 一行一行读取 int num2[5]= {}; freed(num2,sizeof(num2),1,fp); for (int i = 0; i<5; i++){ printf("%d",num2); } //关闭 fclost(fp); */ #include int main (){FILE*fp =fopen( "C:\\Users\\33573\\Desktop\\test.txt","a+"); int num[5] = {1,2,3,5,5}; fwrite( num,sizeof(num),1,fp); //fputs("hello world",fp); return 0; }

头文件与实现文件实例之计算器
  1. 程序的入口函数
    main.cpp 为了让阅读者知道我这里面写的是入口函数
  2. 将不同的功能模块用不同的.h.cpp 来封装
    .h 头文件 函数声明 (不能实现)
    .cpp .c 实现文件 函数的具体实现{}
  3. 导入头文件进行使用
主函数 :头文件
#include //1.程序的入口函数 //main.cpp 为了让阅读者知道我这里面写的是入口函数//2.将不同的功能模块用不同的.h.cpp 来封装 //.h头文件函数声明 (不能实现) //.cpp .c实现文件 函数的具体实现{} // 3. 导入头文件进行使用 #include "calculator.h" int main(){ int a,b; scanf("%d %d" ,&a,&b); int result = add(a,b) ; printf("a + b = %d\n",result); printf("a + b = %d\n",add(a,b)); printf("a - b = %d\n",minus(a,b)); printf("a * b = %d\n",mulitply(a,b)); printf("a / b = %d\n",devide(a,b)); return 0; }

实现文件
//1. 先导入需要的头文件 //2.实现这个头文件的 所有方法 #include "calculator.h" //加法 int add(int a,int b){ return a + b; } //减法 int minus(int a,int b){ return a - b; } // 乘法 int mulitply(int a,int b) { return a * b; } //除法 int devide (int a,int b){ if (b == 0){ return 0; }else { return a/b; } return 0; }

头文件里声明函数
#include //头文件里声明函数 int add(int a,int b); //加法 int minus(int a,int b); //加法 int mulitply(int a,int b) ; //乘法 int devide (int a,int b); //除法

文件操作训练之字符串查找 头文件
#include #include "myString.h"/* * fafjalfjasdfjsadlf * kfjakfj * fslf * ksdfjlafjalsf */ int main(int argc, const char * argv[]) { char sentence[100] = {}; char word[20] = {}; input(sentence, "请输入语句"); input(word, "请输入查找的单词"); int count = find(sentence, word); printf("出现%d次\n", count); return 0; }

实现文件
#include #include "myString.h"//%s 遇到空格或者\n //scanf不能输入带空格的字符串 //只能自己定义一个输入语句的方法 void myScanf(char *p){ int i = 0; while (1) { char c = getchar(); if (c == '\n') { p[i] = '\0'; break; } p[i] = c; i++; } }void input(char *p, char *des){ //提示用户操作 printf("%s:", des); //输入语句 myScanf(p); }//计算字符串的长度 int length(char *p){ int i = 0; //for (; p[i] != '\0'; i++); while (1) { if (p[i] == '\0') { break; } i++; } return i; }int find(char *sentence, char *word){ //1.获取两个字符串的长度 int sLength = length(sentence); int wLength = length(word); //2.判断查询的字符串长度是否比句子短 if (sLength < wLength) { return 0; } /* hjako jack ,jac; i = 2 jac j = 2 */ int start = 0; int count = 0; for (int i = 0; i < sLength; i++) { //记录当前开始的位置 start = i; //从当前位置开始去和查找的单词进行比较 int j = 0; for(; j < wLength; j++){ //判断j对应的值和start+j比较 if (sentence[start+j] != word[j]) { break; } }//判断怎么出来的 if (j == wLength){ //都相同 //将i的值定位到start+j的位置 i = start + j-1; count++; } }return count; }

导入函数
#include #include "myString.h" void input(char *p,char *des); int find(char *sentence,char *word);

    推荐阅读