C语言这种单细胞编程语言和指针的一些理解
转行做嵌入式也有一段时间了,原来做c#以及一些其它的上层语言, 本想的是也就是仅仅是语法上有点不一样。但是实际使用的切身体会真的是只有自己才知道。很多方面刷新了我对c语言以及计算机结构体系的认知 ,绝对不仅仅是语法不一样那么简单。
关于字符串传递函数引起的
一切源于给函数传递字符串变量这种 原来在其它高级语言地方写的 再常见不过的功能。
1 void changeStr(char * ch)
2 {
3 *(ch + 1) = 'a';
4 }
5
6 //char * cstr = "hello";//报错
7 char cstr[] = "hello";//这种可以
8 //数组也是传的引用函数里面更改的是此处数组的内容这个不用多说
9 changeStr(cstr);
10 printf(cstr);
当然对于这个问题的bug 你百度一下就会有很多帖子 ,基本上呢也会给你讲的大概差不多。如果非要死记硬背的话这种代码:
1 char * ch="hello";
他是以常量的形式存在于环境中的。具体的请看:
https://www.qb5200.com/article/405141.html
https://blog.csdn.net/u013066730/article/details/84231452
https://blog.csdn.net/silently_frog/article/details/96607516
总而言之 char * ch=“hello” 然后再去更改ch里的元素 是一个陷阱,至于这个"hello" 的地址大意估计是由编译器更底层的控制的我们不用管。
又啰嗦一遍 内存地址和数据
归根结底还是 指针的问题。内存地址 值 ,学了单片机后深深的认识到这 其实这就是计算机 汇编 ,还有编程的本质,本质就是内存管理 ,到处的计算机书 操作系统 或者其它方面讲的也都是这个,内存数据处理。单片机入门就是地址上的内存数据处理。c语言中处理字符串总是会遇到各种各样的问题也是因为没理解透。
还是返回c语言字符串的议题上来吧
c语言字符串的本质:需要一段连续地址的值 以\0结尾。处理的时候不要超出这个概念。以前在技术群里讨论也模糊的记得 有这个说法 ,上面的"hello"编译后是作为静态字符串存储的,在各处如果写的一模一样的"hello"那么他们在内存里本身就是同一个东西, "hello" 这种以引号引起来的 表示方式 它本质就代表了一个地址标识。另外一个"hello" 这种形式的写法编译器末尾会自动给带一个\0结尾 来确定字符串结束, 这个你是看不见 但他是存在的。依稀记得很久以前学Java时老师说string这个对象怎么是经过封装了的,巴拉巴拉,string本身分配了就是固定的数组了不允许再更改了巴拉巴拉,string c="a"+"b" 实际上是创建了3个对象巴拉巴拉。c++里也看到了确实是包装过的对象类型,但是=号运算方式是按照值类型的处理方式运作的,也即原字符串数据完全复制一遍。再贴一遍字符串的代码:
1 char * str2 = "hello";
一些坑以及产生的原因(指针与分配确切空间):
而c语言指针不允许你指针随便指向一个未初始化的 地址,并不允许你一个指针随意指向一个地址 然后去修改 值 ,这是不被允许的 ,千言万语 归咎于此的根本原因。
1 char ch1 = 0x65;
2 char ch2 = 0x66;
3 char ch3 = 0x00;
4
5 char str1[] = "hello";//{ ch1, ch2, ch3 }这种写法意思是一样的
6 char * str2 = "hello";
7 str1[1] = 'a';
8 //*(str1 + 1) = 'a';数组指针式操作 老套路
9
10 //str2[1] = 'a';//报错
11 //*(str2 + 1) = 'a';//我们想当然的指针地址++ 进行操作是不行的
12 //str2 = &ch1;//这种是可以 但是指向单个字符地址 并不能形成连续的字符串
13
14 printf("%s--\r\n", str1);
15 printf("%s--\r\n", str2);//字符串参数给的是地址
16 printf("%c--\r\n", *str2);//注意字符参数给的是*p
这也是为什么数组字符串 能够 更改元素 (数组的内存空间是确切的),char* (内存空间不确切?内容是放在静态区的?) ,所以不能随意更改。一切都归咎于内存管理, 使用内存时必须必须必须要固定的确切的 经过分配了的 确定的 空间。然后另一个 他们的这种指针的机制是相同的 所以 数组可以用 *p 的形式来访问。
1 int a = 44;
这个 a看似平平无奇 ,实际上这是一个内存空间确定的过程 , a代表了一个地址,编译过程只不过把这个过程变成了对应的汇编指令。
字符串不就是连续地址的值以\0结尾吗 ,于是乎有些大聪明就有了这种代码:
1 char ch1 = 'a';
2 char * str1;
3 char * str2;
4 char * str3;
5
6 str1 = &ch1;
7 str2 = str1 + 1;
8
9 //这样更是错误,指针只能指向一个 给一个地址值
10 //char * str2 = { 'h', 'e', '\0' };
11
12 //还想到 不是连续的指针 么 数组么 ,于是大聪明 这样
13 //又犯了迂回的错误 ,数组 里面 每一个元素都是指针 ,这其实是一个二维数组。
14 //char * str1[]
单片机中除了有定义的外设寄存器以外 ,普通区域 谁允许你擅自通过地址+1的方式 去访问未知的区域的。而单独一个char 一个char 的定义 变量又不可能 给你分配到连续的区域 让你char*去关联上,这是由于c语言本身的机制决定的 ,所以我们就不要去专这个牛角尖了。
也正是由于指针跟数组的相关性 ,指针跟数组有时候 实参 形参可以互相换,比如最开始的代码 形参定义的是指针 确可传数组,定义的是数组也可以传指针 都是可以的 是等价的 ,都相安无事 ,前提是你要自己眼睛看仔细了 传进去的是一个char * 的话 如果你函数内部 进行了元素更改的话 你就挂了。
因为这这些缺陷种种限制, 所以微量氧里到处都是用的数组 形式的字符串,数组就是一串连续确切空间地址的指针。
关于返回一个数组
当然 通过单片机函数不能返回数组 ,只可返回指针 ,返回一个指针么指向那里?函数大括号里的部分在函数运行结束就会被销毁,去哪里找 。
1 char * getChPointer()
2 {
3 //如果想使此函数起作用可以把cc定义成全局的
4 //static char cc = 'b';
5 char cc = 'b';
6 char * ch;
7 ch = &cc;
8 //其实c这种单细胞难用玩意儿,也没啥动态内存分配不动态内存分配
9 //单片机编程中根本就没用到动态内存也就是堆,管理太复杂了。
10
11 //到此方法体内所有的都是复制的 ,包括指针 则复制一模一样的指针
12 //每次调用方法都是独立副本运行,方法结束栈结束 所有内容销毁
13
14 //当栈结束时返回的是复制的跟ch一模一样的指针 都指向cc所以没区别
15 return ch;
16 }
17 char * ch = getChPointer();
18 printf("dd\r\n");
19 printf("%c", *ch);
c语言 真的非常非常的低能 单细胞动物 。深深的感受到c 语言为什么仅仅只是汇编的抽象 ,真是一种单细胞思考方式 ,因为真的是在是太低级了 ,跟其他什么Java相比真的是低一个级别的。诸多限制,更偏向于一种野人式的,要求你的功力要更高才能驾驭。也正是由于这种第一个级别 所有的这些不顺手都不得不逼着你去想 底层到底是怎么运作的。
C语言这种单细胞编程语言和指针的一些理解的更多相关文章
- 关于c语言二维数组与指针的个人理解及处理办法。
相信大家在学习C语言时,对一维数组和指针的理解应该是自信的,但是,我在学习过程中,看到网上一些博文,发现即便是参加工作的一些专业编程人员,突然碰到二维数组和指针的问题时,也可能会遇到难以处理的诡异问题 ...
- C语言 第八章 函数、指针与宏
一.函数 函数是一个包含完成一定功能的执行代码段.我们可以把函数看成一个"黑盒子", 你只要将数据送进去就能得到结果, 而函数内部究竟是如何工作的的, 外部程序是不知道的.外部程序 ...
- c++/java/c# 几种编程语言的指针、引用比较
前一段时间,我在 cnblogs 别人的博客中,谈到: java 中的引用/指针,与 c++/C# 中的引用/指针不是一个概念. Java 引用,相当于 c++ 指针(fun3).Java 引用可以赋 ...
- C语言一维指针的深入理解
指针是C语言中广泛使用的一种数据类型.运用指针编程是C语言最主要的风格之一. 利用指针变量可以表示各种数据结构:能很方便地使用数组和字符串:并能象汇编语言一样处理内存地址,从而编出精练而高效的程序.指 ...
- 娓娓道来c指针 (0)c语言的梦魇:c指针
(0)c语言的梦魇:c指针 序 c语言中有一个重点:c指针.它也是一个难点.当然,这是一句废话:重点往往也是难点.在c标准中,对指针的定义是这种: 指针的类型是derived from其他类型,也就是 ...
- C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | IT宅.com
原文:C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | IT宅.com C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | I ...
- C语言第12轮:指针
C语言第12轮:指针 [学习目标] 1. 指针 2. 指针与数组 A: 指针的概念 内存存储单元按字节排序.每一个字节编有序号.我们称之为地址.因为能够通过地址就能够找到所 ...
- Go语言学习笔记九: 指针
Go语言学习笔记九: 指针 指针的概念是当时学C语言时了解的.Go语言的指针感觉与C语言的没啥不同. 指针定义与使用 指针变量是保存内存地址的变量.其他变量保存的是数值,而指针变量保存的是内存地址.这 ...
- C语言 字符数组与字符指针比较
C语言 字符数组与字符指针比较 #include<stdio.h> /* 字符数组会在定以后预先分配内存空间字符串是常量所以会直接把字符串拷贝到数组中, 因为数组地址不同,所以不相等· 字 ...
- C语言的指针移动怎么理解
C Primer pkus(第五版)中文版,老外写的还是很经典的,推荐给朋友们,购买地址:C primer plus 5版中文版购买 另外再推荐本书: 程序员面试宝典(第5版)第五版:程序员面试宝典( ...
随机推荐
- element 动态合并表格---进阶版
错误展示 正确展示 如果使用上次博客写的element 动态合并表格那么会出现上述图片情况,所以对其进行完善实现下图(正确展示)情况 处理函数 mergeTableRow(data, merge) { ...
- typescript 接口和对象类型(四)
在typescript中,我们定义对象的方式要用关键字interface(接口), 使用interface来定义一种约束,让数据的结构满足约束的格式.定义方式如下: // 定义一个接口类型 int ...
- FreeRTOS LIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 存在的意义以及高于它的中断不能调用 safe freertos api
This is how I understand it. 我是这样理解的. If we now have 2 tasks and 6 interrupts, among which, and when ...
- manim边做边学--圆柱体
Cylinder是Manim中用于创建圆柱体对象的类. Cylinder类在制作数学.物理或工程领域的动画时,可用于以下的场景中: 演示几何概念:使用Cylinder类创建圆柱体,并通过改变其参数和方 ...
- 关于被static修饰还可序列化的问题
今天为了验证一下被static修饰的变量到底可不可以序列化,出现了以下的情况: 然后找到一条评论,豁然开朗 把序列化的内容注释掉,直接从序列化文件读取对象,就发现没有获取到
- 探索 Spring AOP:全面解析与实战应用
在现代 Java 开发领域,Spring 框架无疑占据着重要地位,而 Spring AOP(Aspect-Oriented Programming,面向切面编程)作为 Spring 框架的关键特性之一 ...
- 《刚刚问世》系列初窥篇-Java+Playwright自动化测试-7-元素基础定位方式-下篇 (详细教程)
1.简介 上一篇主要是讲解我们日常工作中在使用Playwright进行元素定位的一些比较常用的基础定位方式的理论基础知识以及在什么情况下推荐使用.今天这一篇讲解和分享一下剩下部分的基础定位方式. 2. ...
- (已解决)Public Key Retrieval is not allowed异常
Public Key Retrieval is not allowed解决方法Public Key Retrieval is not allowed解决方法项目场景:问题描述:原因分析:解决方案:Pu ...
- opencv_contrib编译:fatal error: opencv2/xfeatures2d/cuda.hpp: No such file or directory
在Ubuntu上编译opencv3.4.2源码时,遇到下面的错误,错误1:/home/src/software/opencv-3.4.2/modules/stitching/include/openc ...
- 基于C#实现串口通信Demo
原文链接:基于C#实现串口通信Demo