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版)第五版:程序员面试宝典( ...
随机推荐
- The 2024 ICPC Asia East Continent Online Contest (II) K.Match
题面 K.Match 给定长度为 \(n\) 的两个序列 \(a\) 和 \(b\),当且仅当 \(a_i ⊕ b_j ≥ k\) 时,\(a_i\) 与 \(b_j\) 连一条双向边,其中 \(⊕\ ...
- NewStar CTF 2024 Crypto
Week1 xor #As a freshman starting in 2024, you should know something about XOR, so this task is for ...
- 前端实战之使用canvas合并图片
最近做一个完整的系统,前端中涉及到一个推广图片的生成,其中推广图片是由一个变化的链接生成的二维码与一个固定图片拼接而成 实现demo: qrcode.png:https://images.cnblog ...
- 同步工具之Vector
官网: https://vector.dev/ 用于构建可观察性管道的轻量级.超快速工具 [安装] curl --proto '=https' --tlsv1.2 -sSf https://sh.ve ...
- Django之添加prometheus监控
1.首先需要在prometheus.yml配置文件中配置targets: - job_name: "test-server-191" static_configs: - targe ...
- 使用SharpCompress压缩,tar.gz
之前我们介绍了如何用SharpZipLib来打.tar.gz压缩包. 但是这个压缩软件有两个问题,一是代码比较多,压缩起来没有那么方便:二是压缩的.tar.gz在linux上解压时会有警告,需要跳过这 ...
- Android运行时请求权限封装
@ 目录 1 介绍 2 测试用例设计 3 实现 4 用例测试 5 总结 本文目的:"借助透明Activity封装一个易于调用的权限请求模块" 1 介绍 Android权限的校验和申 ...
- ZCMU-1156
思路: 要改变的是一个范围的情况,所以正常情况下会超时. 查阅后知道应该用一个叫做树状数组的结构. 查阅和树状数组的后续情况 这个也不错 注意: 我没怎么看懂,可能没太仔细看. 树状数组当中存在的是前 ...
- DTL事务控制语言--sql事务
DTL事务控制语言体格sql语句就是一个事务事务可以保证 一组sql语句要么都成功,要么都失败默认自动提交一可以关闭 set autocommit=0关闭自动提交最后 插入或者修改时 只有commit ...
- BUU get_started_3dsctf_2016
先checksec一下 32位程序,没开PIE,再观察一下主函数 gets函数有可能是栈溢出,再观察一下后门函数 方法一: 考虑栈溢出后直接跳转到if判断后面的语句,进而跳过if条件判断 from p ...