By create_string_buffer, create_unicode_buffer let C language has the ability to modify the string

Modify the string

We know that this concept does not exist C string, the string in python in C is achieved by an array of characters. We say to create an array of characters in C, there are two ways:

char *s1 = "hello world";
char s2[] = "hello world";

The results of these two methods, although printing is the same, and s1, s2 point corresponding to the first address of the array of characters, but the internal structure is indeed different.

  • 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快。

So we say char *san array of characters created in this way in C can not be changed, but we can do it by ctypes to char *sbe modified:

#include <stdio.h>

int test(char *s1, char s2[6])
{   
    //两种方式都进行修改
    s1[0] = 'a';
    s2[0] = 'a';
    printf("s1 = %s, s2 = %s\n", s1, s2);
}

We will be compiled into a C file 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

We see both ways successfully modified, but even can modify, we do not recommend it. Not to say not to modify, but rather a different way. If you need to modify, then do not use c_char_p way to pass, but is recommended to transfer to the C language can be modified by a space character create_string_buffer.

create_string_buffer

create_string_buffer is a function ctypes represent that create character has a certain cache size, it can be understood as an array of characters.

from ctypes import *

# 传入一个int,表示创建一个具有固定大小的字符缓存,这里是10个
s = create_string_buffer(10)
# 直接打印就是一个对象
print(s)  # <ctypes.c_char_Array_10 object at 0x000001E2E07667C0>
# 也可以调用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

If you only pass a course create_string_buffer int, it represents the creation of the character corresponding to the cache length. In addition, you can specify a string of bytes, then the size of the character buffer size and the specified string of bytes is the same:

from ctypes import *

# 此时我们直接创建了一个字符缓存
s = create_string_buffer(b"hello")
print(s)  # <ctypes.c_char_Array_6 object at 0x0000021944E467C0>
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 course can also specify byte string while the specified space.

from ctypes import *

# 此时我们直接创建了一个字符缓存,如果不指定容量,那么默认和对应的字符数组大小一致
# 但是我们还可以同时指定容量,记得容量要比前面的字节串的长度要大。
s = create_string_buffer(b"hello", 10)
print(s)  # <ctypes.c_char_Array_10 object at 0x0000019361C067C0>
print(s.value)  # b'hello'
# 长度为10,剩余的5个显然是\0
print(s.raw)  # b'hello\x00\x00\x00\x00\x00'
print(len(s))  # 10

Let us look at how to use create_string_buffer to pass:

#include <stdio.h>

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

At this point it is successfully modified, b we have here "hello" accounted for five bytes, the next place is just the index 5, then put into the corresponding character index section 5-11 of. But attention is that we must be careful \0, we know that in the event of the C language \0would indicate that the array of characters over.

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 <stdio.h>
#include <string.h>
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 <stdio.h>
#include <string.h>
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。。。。。。

Guess you like

Origin www.cnblogs.com/traditional/p/12238984.html