转行做嵌入式也有一段时间了,原来做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语言这种单细胞编程语言和指针的一些理解的更多相关文章

  1. 关于c语言二维数组与指针的个人理解及处理办法。

    相信大家在学习C语言时,对一维数组和指针的理解应该是自信的,但是,我在学习过程中,看到网上一些博文,发现即便是参加工作的一些专业编程人员,突然碰到二维数组和指针的问题时,也可能会遇到难以处理的诡异问题 ...

  2. C语言 第八章 函数、指针与宏

    一.函数 函数是一个包含完成一定功能的执行代码段.我们可以把函数看成一个"黑盒子", 你只要将数据送进去就能得到结果, 而函数内部究竟是如何工作的的, 外部程序是不知道的.外部程序 ...

  3. c++/java/c# 几种编程语言的指针、引用比较

    前一段时间,我在 cnblogs 别人的博客中,谈到: java 中的引用/指针,与 c++/C# 中的引用/指针不是一个概念. Java 引用,相当于 c++ 指针(fun3).Java 引用可以赋 ...

  4. C语言一维指针的深入理解

    指针是C语言中广泛使用的一种数据类型.运用指针编程是C语言最主要的风格之一. 利用指针变量可以表示各种数据结构:能很方便地使用数组和字符串:并能象汇编语言一样处理内存地址,从而编出精练而高效的程序.指 ...

  5. 娓娓道来c指针 (0)c语言的梦魇:c指针

    (0)c语言的梦魇:c指针 序 c语言中有一个重点:c指针.它也是一个难点.当然,这是一句废话:重点往往也是难点.在c标准中,对指针的定义是这种: 指针的类型是derived from其他类型,也就是 ...

  6. C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | IT宅.com

    原文:C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | IT宅.com C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | I ...

  7. C语言第12轮:指针

    C语言第12轮:指针 [学习目标] 1.        指针 2.        指针与数组 A: 指针的概念 内存存储单元按字节排序.每一个字节编有序号.我们称之为地址.因为能够通过地址就能够找到所 ...

  8. Go语言学习笔记九: 指针

    Go语言学习笔记九: 指针 指针的概念是当时学C语言时了解的.Go语言的指针感觉与C语言的没啥不同. 指针定义与使用 指针变量是保存内存地址的变量.其他变量保存的是数值,而指针变量保存的是内存地址.这 ...

  9. C语言 字符数组与字符指针比较

    C语言 字符数组与字符指针比较 #include<stdio.h> /* 字符数组会在定以后预先分配内存空间字符串是常量所以会直接把字符串拷贝到数组中, 因为数组地址不同,所以不相等· 字 ...

  10. C语言的指针移动怎么理解

    C Primer pkus(第五版)中文版,老外写的还是很经典的,推荐给朋友们,购买地址:C primer plus 5版中文版购买 另外再推荐本书: 程序员面试宝典(第5版)第五版:程序员面试宝典( ...

随机推荐

  1. 如何使用建造者模式(Builder Pattern)创建不可变类

    本文由 ImportNew - 唐小娟 翻译自 Journaldev.如需转载本文,请先参见文章末尾处的转载要求. ImportNew注:如果你也对Java技术翻译分享感兴趣,欢迎加入我们的 Java ...

  2. Redis之过期删除侧率

    Redis 中 key 的过期删除策略 内存碎片如何产生 碎片率的意义 如何清理内存碎片 内存淘汰触发的最大内存 有哪些内存淘汰策略 内存淘汰算法 LRU LFU 1.定时删除 2.惰性删除 3.定期 ...

  3. Python3之常用包汇总

    Python包网站: https://pypi.org/ 1. 繁体与简体转换(https://github.com/berniey/hanziconv.git) pip install hanzic ...

  4. 【JS篇】控制子集超过一定数量开始轮播

    [JS篇]控制子集超过一定数量开始轮播, 这个是很早的时候的一个效果了,经过代码的不断迭代升级修改,现在是最封装的一版本,通过面向对象传参数,适用于任何一个需要放置 数量达到一定条件后可执行的函数 / ...

  5. 如何在 duxapp 中开发一个兼容 RN 的动画库

    Taro 一直以来都没有一个能兼容 RN 的动画方案,duxapp 中扩展了 createAnimation 方法,让这个方法兼容了 RN 端,下面让我们来看看实现思路 createAnimation ...

  6. k8s强制删除pod节点

    场景 突然get pod的时候,发现一堆的错误,得把它干掉,否则很不爽. 解决方案 正常过期的状态,比如Evicted ,用正常指令 kubectl -n jingu get pods | grep ...

  7. 简单软件架构的一些好处zz

    简单软件架构的一些好处_大数据_Dan Luu_InfoQ精选文章 Wave 是一家价值 17 亿美元的公司,拥有 70 名工程师,该公司的产品是一款加减数字的 CRUD 应用程序.为了与此保持一致, ...

  8. Qt编写嵌入式linux输入法/支持自定义词语和繁体/支持wayland和watson/纯QWidget/界面精美可换肤

    一.功能特点 纯QWidget编写,原创输入法机制,没有任何第三方动态库的依赖. 支持各种Qt版本,包括Qt4.Qt5.Qt6及后续版本. 支持各种编译器,包括mingw.msvc.gcc.clang ...

  9. Qt编写地图综合应用31-仪表盘

    一.前言 用Qt开发仪表盘控件非常方便,无论是用widget的painter还是qml,尤其是qml,内置的那些动画效果非常适合做这类的应用,这次不讨论如何用qt开发仪表盘,而是直接用echart内置 ...

  10. Qt编写安防视频监控系统49-多数据库支持

    一.前言 数据库设置模块,因为很多项目都会用到,索性这期间也将这玩意重新架构了一遍,对应的数据库组件同样重写了一遍,关于数据库的参数无非就6个,数据库类型(sqlite.mysql等).数据库名称.主 ...