c语言修改字符串c2133,通过create_string_buffer、create_unicode_buffer让C语言具备修改字符串的能力...

字符串的修改

我们知道C中不存在字符串这个概念,python中的字符串在C中也是通过字符数组来实现的。我们说在C中创建一个字符数组有两种方式:

char *s1 = "hello world";

char s2[] = "hello world";

这两种方式虽然打印的结果是一样的,并且s1、s2都指向了对应字符数组的首地址,但是内部的结构确是不同的。

1.char *s1 = "hello world";此时这个字符数组是存放在静态存储区里面的,程序编译的时候这块区域就已经确定好了,静态存储区在程序的整个运行期间都是存在的,主要用来存放一些静态变量、全局变量、常量。因此s1只能够访问这个字符数组,却不能够改变它,因为它是一个常量。而char s2[] = "hello world";,这种方式创建的字符数组是存放在栈当中的,可以通过s2这个指针去修改它。

2.char *s1 = "hello world";是在编译的时候就已经确定了,因为是一个常量。而char s2[] = "hello world";则是在运行时才确定。

3.char *s1 = "hello world";创建的字符数组存于静态存储区,char s2[] = "hello world";创建的字符数组存储于栈区,所以s1访问的速度没有s2快。

d1de7e9df5d8d2f42e87252f720727b3.png

7ad04be2f8ebaec24996f4e8e75affd5.png

所以我们说char *s这种方式创建的字符数组在C中是不能修改的,但是我们通过ctypes却可以做到对char *s进行修改:

#include

int test(char *s1, char s2[6])

{

//两种方式都进行修改

s1[0] = 'a';

s2[0] = 'a';

printf("s1 = %s, s2 = %s\n", s1, s2);

}

我们还是将C文件编译成mmp.dll

import ctypes

from ctypes import *

lib = ctypes.CDLL("./mmp.dll")

# 我们看到无论是char *s1,还是char s2[...],我们都可以使用c_char_p这种方式传递

lib.test(c_char_p(b"hello"), c_char_p(b"hello")) # s1 = aello, s2 = aello

我们看到两种方式都成功修改了,但是即便能修改,我们不建议这么做。不是说不让修改,而是应该换一种方式。如果是需要修改的话,那么不要使用c_char_p的方式来传递,而是建议通过create_string_buffer来给C语言传递可以修改字符的空间。

create_string_buffer

create_string_buffer是ctypes提供的一个函数,表示创建具有一定大小的字符缓存,就理解为字符数组即可。

from ctypes import *

# 传入一个int,表示创建一个具有固定大小的字符缓存,这里是10个

s = create_string_buffer(10)

# 直接打印就是一个对象

print(s) #

# 也可以调用value方法打印它的值,可以看到什么都没有

print(s.value) # b''

# 并且它还有一个raw方法,表示C语言中的字符数组,由于长度为10,并且没有内容,所以全部是\x00,就是C语言中的\0

print(s.raw) # b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

# 还可以查看长度

print(len(s)) # 10

当然create_string_buffer如果只传一个int,那么表示创建对应长度的字符缓存。除此之外,还可以指定字节串,此时的字符缓存大小和指定的字节串大小是一致的:

from ctypes import *

# 此时我们直接创建了一个字符缓存

s = create_string_buffer(b"hello")

print(s) #

print(s.value) # b'hello'

# 我们知道在C中,字符数组是以\0作为结束标记的,所以结尾会有一个\0,因为raw表示C中的字符数组

print(s.raw) # b'hello\x00'

# 长度为6,b"hello"五个字符再加上\0一共6个

print(len(s))

当然create_string_buffer还可以指定字节串的同时,指定空间大小。

from ctypes import *

# 此时我们直接创建了一个字符缓存,如果不指定容量,那么默认和对应的字符数组大小一致

# 但是我们还可以同时指定容量,记得容量要比前面的字节串的长度要大。

s = create_string_buffer(b"hello", 10)

print(s) #

print(s.value) # b'hello'

# 长度为10,剩余的5个显然是\0

print(s.raw) # b'hello\x00\x00\x00\x00\x00'

print(len(s)) # 10

下面我们来看看如何使用create_string_buffer来传递:

#include

int test(char *s)

{

//变量的形式依旧是char *s

//下面的操作就是相当于把字符数组的索引为5到11的部分换成" satori"

s[5] = ' ';

s[6] = 's';

s[7] = 'a';

s[8] = 't';

s[9] = 'o';

s[10] = 'r';

s[11] = 'i';

printf("s = %s\n", s);

}

from ctypes import *

lib = CDLL("./mmp.dll")

s = create_string_buffer(b"hello", 20)

lib.test(s) # s = hello satori

此时就成功地修改了,我们这里的b"hello"占五个字节,下一个正好是索引为5的地方,然后把索引为5到11的部分换成对应的字符。但是需要注意的是,一定要小心\0,我们知道C语言中一旦遇到了\0就表示这个字符数组结束了。

from ctypes import *

lib = CDLL("./mmp.dll")

# 这里把"hello"换成"hell",看看会发生什么

s = create_string_buffer(b"hell", 20)

lib.test(s) # s = hell

# 我们看到这里只打印了"hell",这是为什么?

# 我们看一下这个s

print(s.raw) # b'hell\x00 satori\x00\x00\x00\x00\x00\x00\x00\x00'

# 我们看到这个create_string_buffer返回的对象是可变的,在将s传进去之后被修改了

# 如果没有传递的话,我们知道它是长这样的。

"""

b'hell\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

hell的后面全部是C语言中的\0

修改之后变成了这样

b'hell\x00 satori\x00\x00\x00\x00\x00\x00\x00\x00'

我们看到确实是把索引为5到11(包含11)的部分变成了"satori"

但是我们知道C语言中扫描字符数组的时候一旦遇到了\0,就表示结束了,而hell后面就是\0,

因为即便后面还有内容也不会输出了,所以直接就只打印了hell

"""

另外除了create_string_buffer之外,还有一个create_unicode_buffer,针对于wchar_t,用法和create_string_buffer一样。

C语言中查看字符数组的长度

C语言中如何查看字符数组的长度呢?有两种方法,一种是通过sizeof,一种是通过strlen。话说我说这个干什么?算了,不管了。

#include

#include

int main() {

char s[] = "hello world";

//C语言中查看字符串的长度可以使用strlen,这个需要导入string.h头文件。strlen计算的就是字符的个数,不包括\0

//使用sizeof计算的结果是包含\0的,所以会比strlen计算的结果多1

printf("%d %d\n", strlen(s), sizeof(s) / sizeof(s[0])); // 11 12

return 0;

}

但是我们发现字符数组的创建方式是通过char s[]这种形式,如果是char *s呢?

#include

#include

int main() {

char *s = "hello world";

printf("%d %d\n", strlen(s), sizeof(s) / sizeof(s[0])); // 11 8

return 0;

}

我们看到使用strlen计算的结果是一样的,但是使用sizeof得到的结果却是不一样的。因为char *s,这个s我们虽然可以使用它来打印字符数组,但它本质上是一个指针,一个指针在64位机器上占8个字节,所以结果是8。而char s[]中的s虽然也指向字符数组的首地址,但它本质上是一个数组名,我们使用sizeof查看得到的结果还是字符数组中所有元素的总大小。

艾玛,你扯到C上面干啥。。。。。。你又不会C。。。。。。

66931f25e41327194f45bfbd9d113fd9.png

来源:https://www.cnblogs.com/traditional/p/12238984.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/559913.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c语言中O空字符,OC语言中字符串的使用

可变字符串//插入字符串NSMutableString*string1 [NSMutableStringstringWithString:"字符串"];[string1insertString:"可变"atIndex:0];//在string的第0个位置插入NSLog("string %",string1);//可变字符串//删除字符串NSMutableString*string2…

大二c语言期末考试题库及详解答案,大学C语言期末考试练习题(带详解答案)...

《大学C语言期末考试练习题(带详解答案)》由会员分享,可在线阅读,更多相关《大学C语言期末考试练习题(带详解答案)(55页珍藏版)》请在金锄头文库上搜索。1、一、 单项选择题1( A )是构成C语言程序的基本单位。A、函数 B、过程 C、子程序 D、子例程2C语言…

C语言指针怎么存二维数组,C语言怎么用指针代替二维数组

1.设p是指向二维数组a[m][n]的指针变量,则有:int*pa[0];//此时P是指向一维数组的指针。P后,p指向a[0][1]。2.如果定义int(*p1)[n];p1a;p1后,p1指向a[1][0];则pj将指向a[0]数组中的元素a[0][j]。由于a[0]、a[1]┅a[M-1]等各个行数组…

c语言结构引用6,C语言6结构体练习题6

第六章 结构体1.下面对结构变量的叙述中错误的是A.相同类型的结构变量间可以相互赋值 B.通过结构变量,可以任意引用它的成员 C.结构变量中某个成员与这个成员类型相同的简单变量间可相互赋值D.结构变量与简…

设 l í {a,b,c}* 是满足下述条件的符号串构成的语言,编译原理模拟试题1和2的答案...

一、是非题1、算符优先关系表不一定存在对应的优先函数。( 错)2、数组元素的地址计算与数组的存储方式有关。( 错)3、仅考虑一个基本块,不能确定一个赋值是否真是无用的。( 正确)4、每个文法都能改写为LL(1)文法。( 正确)。5、对于数据空间的存贮分配,FO…

新手学习c语言的方法,学习C语言方法“新手必看”

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼1、多看代码在有一定基础以后一定要多看别人的代码。 注意代码中的算法和数据结构。 毕竟学C之后的关口就是算法和数据结构。提到数据结构,指针是其中重要的一环,绝大多数的数据结构是建立在指针…

android自定义进度条百分比跟着走,Android自定义View实现水平带数字百分比进度条...

这个进度条可以反映真实进度,并且完成百分比的文字时随着进度增加而移动的,所在位置也恰好是真实完成的百分比位置,效果如下:思路如下:第一部分是左侧的蓝色直线,代表已经完成的进度;第二部分是…

android动画view上移,在Android开发中使用View制作一个引导动画

在Android开发中使用View制作一个引导动画发布时间:2020-11-20 16:46:16来源:亿速云阅读:98作者:Leah这篇文章将为大家详细讲解有关在Android开发中使用View制作一个引导动画,文章内容质量较高,因此小编分享…

linux 启动 x,(1)linux启动过程

head.S是linux启动后的第一个文件,主要完成以下功能:1、检查处理器信息,并保存;2、检查平台号,并保存;3、创建页表,并开启MMU功能;4、对内核data section、bbs section作调整和初始化…

android 刷新view位置,Android View刷新机制实例分析

本文实例讲述了Android View刷新机制。分享给大家供大家参考,具体如下:一、总体说明在Android的布局体系中,父View负责刷新、布局显示子View;而当子View需要刷新时,则是通知父View来完成。二、代码分析1).ViewGroup的a…

android 滚动到底部,Android 控制ScrollView滚动到底部(示例代码)

在开发中,我们经常需要更新列表,并将列表拉倒最底部,比如发表微博,聊天界面等等,这里有两种办法,第一种,使用scrollTo():public static void scrollToBottom(final View scroll, final View inner) {Handler mHandler …

html整体引入js,html页面用js引入js的方式

最原始的是用script便签:1. 使用js打印这个便签:当然这也可以动态引入css以及其他html元素。2. 使用dom的api添加script元素:jQuery中封装了这种方式,并贴心的加入了回调:$.getScript(url,callback(res, status));简单…

vivo android p 机型,vivo X21成全球首批Android P适配机型!vivo :不小心就秀实力了

原标题:vivo X21成全球首批Android P适配机型!vivo :不小心就秀实力了近日,2018谷歌I/O大会正式召开,会上发布了大家期待已久的Android P开发者预览版,给我们展示了众多全新特性,其中AI功能的进化让人十分眼…

android继承父类的界面,Android调用父类方法,进行子界面刷新

偶然遇到一个需求、有几个主界面需要获取消息的未读数量由于不是所有类都调用、调用的次数又比较多,整的不上不下的1、对于方法调用次数比较少的 推荐广播广播的方法很方便、但是一堆的消息接收、发送很模式化2、对于较多的方法调用 个人建议直接写共用类中此方法通…

html中依次展开的搜索框,jQuery+CSS3动画展开收缩搜索框特效

js代码function searchToggle(obj, evt){var container $(obj).closest(.search-wrapper);if(!container.hasClass(active)){container.addClass(active);evt.preventDefault();}else if(container.hasClass(active) && $(obj).closest(.input-holder).length 0){con…

直接修改html文本页面没变化,VUE 直接通过JS 修改html对象的值导致没有更新到数据中解决方法分析...

本文实例讲述了VUE 直接通过JS 修改html对象的值导致没有更新到数据中解决方法。分享给大家供大家参考,具体如下:业务场景我们在使用vue 编写 代码时,我们有一个 多行文本框控件,希望在页面点击一个按钮 在 文本框焦点位置插入一个…

html.partial传递模型,Html.Partial和Html. RenderPartial用法

Html.Partial("MyView")Renders the "MyView" view to an MvcHtmlString.Html.Partial通常呈现的是静态内容,如果不指定的Partial方法中绑定的参数,默认为宿主页面的Model类型,因此如果Partial页面中的Model和主页面的Mo…

live2d内嵌html,博客(网页)添加 Live2D 看板娘

Live2D demoLive2D 看板娘插件 (https://www.fghrsh.net/post/123.html) 的前端 HTML 源码基于 API 加载模型,支持 定制 提示语增加 参数设置 一键定制看板娘,易用性增加 看板娘样式设置,可直接设置宽高度等支持多种一言接口,基于…

计算机启动进入不了桌面图标,电脑开机后不显示桌面图标如何通过修改注册表解决问题...

‍近来有用户发现电脑开机后不显示桌面图标,一般遇到这样的问题,我们会进入任务管理器结束explorer.exe资源管理器进程,再重新启动来解决这个问题。但是,如果这样还无法解决不显示电脑系统桌面图标的问题,那么可以按下…

药学专业报计算机一级有用吗,全网友泣泪劝阻!高考结束之后,什么专业千万不能报?...

原标题:全网友泣泪劝阻!高考结束之后,什么专业千万不能报?本文来源:魔都囡啊呀呀呀,高考终于结束啦,大家可以轻松下啦?不过高考的硝烟还没消散,接下来的一个问题就是非常…