太久没有看C语言相关知识了,开始要整理回顾一些重点知识点啦,因为各大公司笔试还是有许多C语言相关的题,做个复习。

const 关键字与指针修饰使用

普通指针使用:

//普通指针使用,我们通过 i 或者 p 指针都能改变变量值
void test1()
{int i = 1;int * p = &i;printf("p=%d\n",*p);i = 2;printf("p=%d\n",*p);(*p)++;printf("p=%d\n",*p);printf("i=%d\n",i);
}

输出结果:

这个结果是我们好理解的。

接着 const int *p 问题

// const int *p 表示p 所指的对象是只读不可以改变的,但p 指针可以指向其他地址
void test2()
{int i = 1;int j = 100;const int * p = &i;printf("p=%d\n",*p);i = 2;printf("p=%d\n",*p);p = &j;printf("p=%d\n",*p);/*(*p)++;// 出错 error:increment of read-only lacation '*p'printf("p=%d\n",*p);*/
}

输出结果:

这里我们发现指针p 我们可以随便调整指向哪块已知的内存空间,但是不能通过 给*p 复制来改变指针所指的对象。

int const *p 和上面const int *p  效果一样这里就不多说啦。

接下来说 int * const p 形式,如下测试代码:

// int * const p 表示指针p 不可修改,但是指针p 所指向的内容可以修改
void test3()
{int i = 1;int j = 100;int * const p = &i;printf("p=%d\n",*p);i = 2;printf("p=%d\n",*p);/*p = &j;// error:assignment of read-only variable 'p'printf("p=%d\n",*p);*/(*p)++;printf("p=%d\n",*p);printf("i=%d\n",i);
}

输出结果:

最后一种情况就是上面情况结合在一起const int * const p 这样就是p 指针无法修改,p 指针所指的内容也无法修改。

C与指针第六章习题

1.

char * find_char(char const * source , char const *chars)
{if(source==NULL || chars==NULL)return NULL;char const * cp;for(;*source!='\0';source++){// 这里每次遍历chars 中内容for(cp=chars;*cp!='\0';cp++){if(*source == *cp)return (char *)source;}}return NULL;
}

实现中发现一个问题:char a[] 与 char *a 的区别

char a[]在运行时赋值,值会从静态区赋值到函数的栈中,对它进行修改不会产生任何问题。char *a在编译时就确定了,a指向静态区中的值,没有赋值到函数栈中, 因此对指针的内容进行修改会产生错误。

这个问题详细解释:http://blog.chinaunix.net/uid-20583479-id-1920067.html
2.

char * match(char * str,char const *substr)
{while(*substr != '\0'){if(*str++ != *substr++)return NULL;}return str;
}
int Del_substr(char *str,char const *substr)
{char * next;char * orig = str;while(*str != '\0'){next = match(str,substr);if(next != NULL)break;str++;}if(*str == NULL)return 0;printf("outside\n");while((*str) != '\0'){*str = *next;str++;next++;}printf("%s\n",orig);return 1;
}

3.

void reverse_string(char *str)
{if(str == NULL)return;char *p = str;int count = 0;char ch;for(;*p!='\0';p++){count++;}p = str;char * end = p + count -1;while(p < end){ch = *p;*p = *end;*end = ch;p++;end--;}*(str+count) = '\0';printf("%s\n",str);
}

指向数组的指针VS指针数组

指向数组的指针:

int vector[10], *vp = vector; 这个声明是合法的,它为整型数组分配内存,并把vp 声明为指向整型的的指针。

int matrix[2][3] matrix 并不是指向整型的的指针,而是一个指向整型数组的指针,我们应该如何声明指向数组的指针?

int (*mp)[3]这里要带上第二维的数据控制,不是mp指针自增操作不确定能跳过多少长度。

int matrix[2][3] = {{1,2,3},{4,5,6}};int *p = &matrix[0][0];printf("%d\n",*p);printf("%d\n",*++p);printf("%d\n",*++p);

如上代码,指针p 指向数组中第一个元素,然后指针自增1 ,指向了第二个数字,所以上面输出就是:1,2,3 ,我们一直要确定好一件事情就是指针类型,因为类型决定了指针自增1是能跳动多大的距离。

int matrix[2][3] = {{1,2,3},{4,5,6}};int (*mp)[3];mp = matrix;printf("%d\n",(*mp)[0]);printf("%d\n",(*mp)[1]);printf("%d\n",(*++mp)[0]);

如上代码:定义mp 为指向拥有3个整型元素的数组的指针,当对mp 与整数相加时,该整数值根据3这个长度调整,所以mp++ 导致指针mp 指向数组下一行数组元素。

所以上述代码输出:1,2,4 这里就可以告诉我们如何去对二维数组元素通过指针进行操作。

指针数组:

正如你可以创建整型数组一样,你也可以声明指针数组,如下面:

int *api[10] ,api 有十个元素,每个元素是指向int 型的指针。

再看个复杂点结构:

char const *keyword[] = {"do","for","if","register","return","switch","while"};

keyword 是一个指针数组,数组中每个元素都指向一个char型数组。当我们需要查找某个关键字时可以遍历该指针数组,如下:

int lookup_keyword(char const * const desired_word,char const *keyword_table[],int const size)
{char const **kwp;/*char (*p)[10];// 这里搞清楚类型啊,keyword_table 是char ***/// 查找kewword_table中每个单词for(kwp = keyword_table;kwp < keyword_table + size;kwp++){printf("%s\n",*kwp);*kwp = "hello";//数组中内容可以改变,所以*kwp 可以指向别的内容if(strcmp(desired_word,*kwp) == 0){return kwp - keyword_table;}}return -1;
}

这里需要注意为什么kwp 定义为指针的指针? 分析一下,keyword_table 是数组起始位置是指针,而数组中元素也是指针,所以当要引用数组中元素时必须定义为指针的指针来遍历该数组。

如果上述结构定义为二维数组这样:

   char const keywordMatrix[][9]={"do","for","if","register","return","switch","while"};

实现上述查找相同功能则需要进行改动:

int lookup_keywordMatrix(char const * const desired_word,char const (*keyword_table)[9],int const size)
{char const (*kwp)[9];for(kwp=keyword_table;kwp<keyword_table+size;kwp++){if(strcmp((char *)kwp,desired_word) == 0){return kwp - keyword_table;}}return -1;
}

首先传参就需要改变,这里定义的 char const(*keyword_table)[9] 是指向char型数组的指针,定义kwp同样需要这样为:char const (*kwp)[9] ,

所以在使用strcmp 函数时需要类型强制转换。

小结:

数组名是指向数组第一个元素的指针。这里有两个例外,sizeof返回整个数组占用的字节而不是一个指针所占用的字节。

int a[] 对 &a 操作返回是指向整个数组的指针。

指针和数组不相等。当我们声明一个数组时,同时就分配了内存空间,但是声明一个指针时,只是分配了容纳指针本身空间。

当数组名作为函数参数传递的,实际传递给函数是指向数组第一个元素的指针。 函数所接收的参数实际为原参数的拷贝,所以函数可以对其进行操纵不影响实际参数,但是执行期间修改数组元素会影响原先数组元素。

结构体与内存分配:

结构体最基本的两种访问方式,关于内存分配,C语言中使用是malloc 和 free 。

malloc函数从内存池中提取一块合适的内存,并向调用程序返回一个指向这块内存的指针。你需要自己手动对这块内存进行初始化,malloc函数分配是一块连续的内存,

使用malloc函数时一定要注意malloc分配内存空间是否成功,如果不成功malloc函数会返回NULL,所以好的编程习惯一定是检查分配内存空间。

此外malloc函数返回是void * 指针,因为这个返回类型问题,我们使用malloc经常会需要强制类型转换。

动态内存常见错误:

NULL指针解引用操作、分配内存操作越界、释放并非动态分配内存、释放一块动态分配内存的一部分、动态内存释放后继续使用等。

通过实际对单向链表操作来熟悉结构体和内存分配。

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;typedef struct LinkList{int value;LinkList * next;
}*ListPoint;void insert_Node(LinkList **head,int value)
{ListPoint pre,current;pre = NULL;current = *head;while(current && current->value < value){pre = current;current = current->next;}LinkList * new_node = (LinkList *)malloc(sizeof(LinkList));//好的编程习惯需要每次分配内存检查if(new_node == NULL){printf("malloc memory error !!!");return;}new_node->value = value;new_node->next = current;// 意味着插入链表起始位置if(pre == NULL){printf("test here\n");*head = new_node;}else{pre->next = new_node;}
}void Print_LinkList(LinkList *head)
{if(head == NULL){printf("empty LinkList\n");return;}while(head !=NULL){printf("%d",head->value);head = head->next;}
}int main()
{int arr[6] = {3,2,1,6,4,5};ListPoint head = NULL;for(int i=0;i<6;i++){insert_Node(&head,arr[i]);}Print_LinkList(head);for(int i=0;i<6;i++){printf("haha\n");}return 0;
}

转载于:https://www.cnblogs.com/huruzun/p/5423881.html

C语言重要知识点回顾相关推荐

  1. 前端知识点回顾——HTML,CSS篇

    前端知识点回顾篇--是我当初刚转行为了面试而将自己学过的前端知识整理成的一份笔记,个人目的性很强,仅供参考. doctype 有什么用 doctype是一种标准通用标记语言的文档类型声明,目的是告诉标 ...

  2. 零基础Python知识点回顾(一)

    如果你是小白,建议只要安装官网的python-3.7.0-amd64.exe 然后在电脑cmd命令提示符  输入检查是否已经安装pip,一般安装了python都会有的. >pip         ...

  3. 考研复试(控制工程专硕)及大学本科(物联网工程)知识点回顾(五)——其他重点内容

    复试所涉及的科目 随机问题 1.过程控制与运动控制的区别? 2.√ 模拟电子技术与数字电子技术的区别? 3.√√ I2C和SPI的区别? 4.推挽输出与开漏输出的区别? 5.√ 可编程逻辑器件与微机的 ...

  4. 刘大拿python_零基础Python知识点回顾(一)

    如果你是小白,建议只要安装官网的python-3.7.0-amd64.exe 然后在电脑cmd命令提示符  输入检查是否已经安装pip,一般安装了python都会有的. >pip         ...

  5. Linux知识点回顾之shell编程

    Linux知识点回顾之shell编程 shell编程 1 基本介绍 1.1 Shell 脚本 1.2 Shell 环境 1.3 第一个shell编程 1.4 运行 Shell 脚本有两种方法: 1.5 ...

  6. Android群英传知识点回顾——第十章:Android性能优化

    Android群英传知识点回顾--第十章:Android性能优化 知识点目录 10.1 布局优化 10.1.1 Android UI渲染机制 10.1.2 避免Overdraw 10.1.3 优化布局 ...

  7. c语言获取指针分配的字节数,c语言指针知识点总结(共6篇).docx

    c语言指针知识点总结(共6篇) C语言指针教学中的知识点分析与总结 摘要:分析指针的基本概念及指针在数组.函数.字符串.动态存储分配等方面的应用,提出指针教学过程中易混淆概念及注意事项,对初学者深入理 ...

  8. 【直播】李祖贤:集成学习答疑直播之八-- 集成知识点回顾与补充

    集成学习答疑直播之八-- 集成知识点回顾与补充 集成学习是首个横跨3个周期的长期组队学习,在第25期组队学习中进行到"第三期-模型融合与数据实战"阶段.组队学习期间,课程设计者每周 ...

  9. 【运筹学】线性规划数学模型 ( 知识点回顾 | 可行解 | 最优解 | 阶梯型矩阵 | 阶梯型矩阵向量 | 基 | 基向量 | 基变量 | 非基变量 )

    文章目录 一.知识点回顾 1.线性规划三要素 2.线性规划一般形式 3.线性规划标准形式 二.线性规划解.可行解.最优解 三.阶梯型矩阵 四.阶梯型矩阵向量 五.基.基向量.基变量.非基变量 一.知识 ...

最新文章

  1. 简单的鼠标可拖动div 兼容IE/FF
  2. 业界 | 5个步骤开启你的数据科学职业生涯!(附链接)
  3. C# 版本 疫情传播仿真程序
  4. 求逆序对(信息学奥赛一本通-T1311)
  5. Bootstrap4代码模板
  6. 验证登录信息是否合法
  7. solaris 关闭、释放socket端口
  8. 枚举Enumerations
  9. 一款被大家低估的微服务场景下性能问题排查神器!
  10. 我的Android第五章:通过Intent实现活动与活动之间的交互
  11. java jdom 类_JDOM 介绍及使用指南
  12. 3Dmax移动,旋转,缩放图标不显示
  13. 天翼网关刷linux,天翼网关3.0-中兴F650光猫最新固件 开Telnet教程
  14. 路由宽带运营商服务器未响应,宽带运营商服务器未响应解决方法
  15. Windows图片和传真查看器修复办法
  16. 你必须知道的指针基础-6.内存的初始化及结构体的使用
  17. 初探深度优化搜索--小白版
  18. Unity XR开发之入门介绍(一)
  19. 实时群控,苹果群控,手机群控,IOS群控,批量手机操作,批量手机控制,同步操作
  20. C++:实现量化Lookback option 回顾式期权测试实例

热门文章

  1. android studio导入jar包
  2. dotnet core 数据库
  3. 无废话WCF系列教程 -- 李林峰
  4. HDU——1418抱歉(平面欧拉公式)
  5. ubuntu - 14.04,如何操作Gnome的任务栏?
  6. 关于sql中去换行符的问题
  7. Windows Installer (MSI) 详解 参数介绍
  8. modelsim仿真
  9. winform下的未捕捉的异常处理
  10. 致:WWF技术博客领跑者WXWINTER--兰竹梅菊.春夏秋冬