char *的一个bug?有不同顺序时产生

本文探讨了在使用Java Native Interface (JNI)进行Java与C/C++混合编程时遇到的问题,特别是关于rf_select3方法的参数传递错误导致的问题。通过调整Java端的方法签名,从使用long类型改为使用NativeLong类型,解决了C++端指针操作引发的错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Thanks for your help :)

 

windows xp x86, jdk 1.6.20

 

hellojna dll project

hellojna.h

 

extern "C" _declspec(dllexport) int swapvalue(int* a, int* b);
extern "C" _declspec(dllexport) int rf_select1(unsigned char *_Size);
extern "C" _declspec(dllexport) int rf_select2(unsigned char *_Size,long icdev);
extern "C" _declspec(dllexport) int rf_select3(long icdev, unsigned char *_Size);

 

hellojna.cpp

 

#include "stdafx.h"
#include "hellojna.h"

int rf_select1(unsigned char *_Size) {
    _Size[0] = 'a';
    return 12;
}

int rf_select2(unsigned char *_Size, long icdev) {
    _Size[0] = 'a';
    return 12;
}

int rf_select3(long icdev, unsigned char *_Size) {
    _Size[0] = 'a';
    return 12;
}

HelloJna.java

 

public interface HelloJna extends Library {
	HelloJna instance = (HelloJna) Native.loadLibrary("hellojna", HelloJna.class);
	int rf_select1(byte[] abd);
	int rf_select2(byte[] abd, long dev);
	int rf_select3(long dev, byte[] abd);
}

Test.java 

public class Test {
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		HelloJna jna = HelloJna.instance;

		byte[] buf = new byte[]{'s', 'u', 'p', 'e', 'r', ' ', 'm', 'a', 'n', '\0'};
		int ret = jna.rf_select1(buf);
		System.out.println("buf=" + new String(buf) + ",ret=" + ret);
		
		buf[0] = 'I';
		ret = jna.rf_select2(buf, 77);
		System.out.println("77 buf=" + new String(buf) + ",ret=" + ret);
		
		buf[0] = 'E';
		ret = jna.rf_select3(99, buf);
		System.out.println("99 buf=" + new String(buf) + ",ret=" + ret);
	}

}

console.out:

 

buf=auper man , ret=12
77 buf=auper man ,ret=12

the screen capter: 


why rf_select1 and rf_select2 is right but rf_select3 is error ??

the differences is just the paramters order??

in the rf_select3 _Size is null

 

buf[0] = 'E';
ret = jna.rf_select3(99, buf);

2010-09-15 00:13 add info:

 

I found it's work good when HelloJna.java change rf_select3(long dev, byte[] abd) to rf_select3(NativeLong dev, byte[] abd)

 

public interface HelloJna extends Library {
	HelloJna instance = (HelloJna) Native.loadLibrary("hellojna", HelloJna.class);
	int rf_select1(byte[] abd);
	int rf_select2(byte[] abd, long dev);
	int rf_select3(NativeLong dev, byte[] abd);
}
详细讲解解析:内存拷贝函数memcpy memcpy是memory copy的缩写,意为内存复制,在写C语言程序的候,我们常常会用到它。它的函原型如下: void *memcpy(void *dest, const void *src, size_t n); AI写代码 c 运行 1 它的功能是从src的开始位置拷贝n个字节的数据到dest。如果dest存在数据,将会被覆盖。memcpy函数的返回值是dest的指针。memcpy函数定义在string.h头文件里。 自己实现的候,最简单的方法是用指针按照字节顺序复制即可。但是性能太低,因为其一,一次一个字节效率太低,地址总线一般是32位,能搬运4字节,一次一个肯定慢的行;其二,当内存区域重叠会出现混乱情况。 一下根据以上两方面考虑提高memcpy函数的性能。首先考虑速度,可以按照CPU位宽搬运数据,效率更高,代码如下: void * Memcpy1(void *dst,const void *src,size_t num) { int nchunks = num/sizeof(dst); /*按CPU位宽拷贝*/ cout<<"sizeof(dst)是:"<<sizeof(dst)<<endl; int slice = num%sizeof(dst); /*剩余的按字节拷贝*/ unsigned long * s = (unsigned long *)src; unsigned long * d = (unsigned long *)dst; while(nchunks--) *d++ = *s++; while (slice--) *((char *)d++) =*((char *)s++); return dst; } AI写代码 c 运行 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 sizeof(dst)是4,即大部分数据每次按照4字节拷贝,最后足4字节的再分别拷贝。但是内存区域出现重叠,这种方法无法规避内存混乱问题。 下面的方法能够规避内存重叠的bug,代码如下: void *Memcpy2(void *dest, const void *src, size_t count) { char *d; const char *s; if (((int)dest > ((int)src+count)) || (dest < src)) { d = (char*)dest; s = (char*)src; while (count--) *d++ = *s++; } else /* overlap */ { d = (char *)((int)dest + count - 1); /* 指针位置从末端开始,注意偏置 */ s = (char *)((int)src + count -1); while (count --) *d-- = *s--; } return dest; } AI写代码 c 运行 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 如果检测到内存区域有重叠部分,则从末端开始对每个字节进行拷贝。但数据量大速度慢,将两种方法结合后能够提高拷贝函数性能,代码如下: void *Memcpy(void *dest, const void *src, size_t count) { cout<<"sizeof(dest)是:"<<sizeof(dest)<<endl; int bytelen=count/sizeof(dest); /*按CPU位宽拷贝*/ int slice=count%sizeof(dest); /*剩余的按字节拷贝*/ unsigned int* d = (unsigned int*)dest; unsigned int* s = (unsigned int*)src; if (((int)dest > ((int)src+count)) || (dest < src)) { while (bytelen--) *d++ = *s++; while (slice--) *(char *)d++ = *(char *)s++; } else /* overlap重叠 */ { d = (unsigned int*)((unsigned int)dest + count - 4); /*指针位置从末端开始,注意偏置 */ s = (unsigned int*)((unsigned int)src + count -4); while (bytelen --) *d-- = *s--; d++;s++; char * d1=(char *)d; char * s1=(char *)s; d1--;s1--; while (slice --) *(char *)d1-- = *(char *)s1--; } return dest; } AI写代码 c 运行 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 对比一下,测试代码如下: int main(){ char a[20]="1133224466558877990"; // Memcpy1(a+2,a,5); // Memcpy2(a+2,a,5); Memcpy(a+2,a,5); cout<<a<<endl; cin.get(); } AI写代码 c 运行 1 2 3 4 5 6 7 8 运行结果: Memcpy1: 1111333466558877990 Memcpy2: 1111332466558877990 Memcpy: 1111332466558877990 后两种方法正确,第一种方法拷贝无法规避内存重叠的bug。 ———————————————— 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,载请附上原文出处链接和本声明。 原文链接:https://blog.youkuaiyun.com/wyk71456/article/details/108424816
最新发布
07-31
<think>用户的问题是如何在C++中动态分配一个char类型指针的数组。结合用户提供的引用内容,我来整理一下相关的信息。从引用[5]中可以看到,使用new分配的内存在超出作用域后会被自动销毁,需要手动delete。引用[4]提供了多维数组的动态分配方法,其中提到了两种方式:分配连续内存块和使用指针数组。引用[3]展示了std::array的使用,但用户明确要求动态分配指针数组,所以std::array可能适用。用户的问题具体是char指针数组,也就是char*数组。引用[2]涉及了从C++返回char数组给Java的场景,但更相关的是如何在C++中创建这样的数组。需要明确指针数组的每个元素都是char*类型,指向字符串。因此动态分配应该分为两步:先分配指针数组本身,再为每个指针分配内存存储具体字符串。引用[4]中的第二种方法适合这种情况:char**array1=newchar*[x];然后为每个array1[i]分配内存。过用户的问题只是关于分配指针数组,涉及后续为每个指针赋值,所以重点在第一步。从引用[5]的代码示例可以看到,使用new分配数组需要使用delete[]释放内存。因此回答中应该包含完整的分配和释放过程。对于数组访问,可以像普通数组一样使用下标操作符访问元素。比如array[0]就是第一个char指针。考虑到用户可能清楚指针数组和二维数组的区别,我应该在回答中明确说明:这里创建的是指针数组(每个元素是char*),而是二维char数组(如char[][])。引用[4]正好提供了这两种情况的对比,我参考第一种情况下的解释来强调这个区别。为了清晰说明,我准备提供一个完整的代码示例:展示如何分配大小为size的char*数组,最后再安全释放内存。同提醒用户注意避免内存泄漏,这与引用[5]强调的手动释放相呼应。</think> 在 C++ 中动态分配一个 `char` 类型指针的数组(即 `char*` 数组),需要遵循以下步骤: ### 1. **声明指针数组** 声明一个指向指针的指针: `char** ptrArray`。 ### 2. **分配指针数组内存** 使用 `new` 分配数组: ```cpp int size = 5; // 示例数组大小 char** ptrArray = new char*[size]; // 分配存放 char* 的数组 ``` ### 3. **为每个指针分配内存** 遍历数组,为每个 `char*` 分配独立的字符串内存: ```cpp for (int i = 0; i < size; ++i) { ptrArray[i] = new char[100]; // 每个指针指向 100 字节的 char 数组 } ``` ### 4. **使用与操作** 像普通二维数组一样访问元素: ```cpp strcpy(ptrArray[0], "Hello"); // 复制字符串到第一个元素 std::cout << ptrArray[0][0]; // 输出 'H' ``` ### 5. **释放内存** 先释放每个指针的内存,再释放指针数组: ```cpp for (int i = 0; i < size; ++i) { delete[] ptrArray[i]; // 释放每个 char 数组 } delete[] ptrArray; // 释放指针数组 ``` --- ### 完整示例代码 ```cpp #include <iostream> #include <cstring> int main() { // 1. 声明并分配指针数组 const int size = 3; char** strArray = new char*[size]; // 2. 为每个指针分配字符串内存 for (int i = 0; i < size; ++i) { strArray[i] = new char[20]; // 每个元素最多存储 19 字符 + '\0' } // 3. 使用数组 strcpy(strArray[0], "C++"); strcpy(strArray[1], "Dynamic"); strcpy(strArray[2], "Array"); for (int i = 0; i < size; ++i) { std::cout << strArray[i] << " "; } // 输出: C++ Dynamic Array // 4. 释放内存 for (int i = 0; i < size; ++i) { delete[] strArray[i]; // 释放每个字符串 } delete[] strArray; // 释放指针数组 return 0; } ``` ### 关键注意事项 1. **内存释放顺序**:必须先释放内部的 `char` 数组,再释放外层的指针数组(逆序释放)[^5]。 2. **内存连续性**:每个 `char*` 指向的内存可能连续(与 `char[][N]` 不同)[^4]。 3. **替代方案**:推荐使用 `std::vector<std::string>` 或 `std::array`(固定大小)避免手动内存管理[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值