我想将两个相同类型的数组连接成一个具有相同类型的新数组。但问题是我必须使用void
指针,不知怎的,我的代码不会从第三个元素开始工作。我在互联网上搜索了一下,但似乎没有人遇到这个问题
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void array_float_fill(float *arr1, float *arr2, int n, int m){
for(int i = 0;i<n;i++){
*(arr1+i)=i+n;
}
for(int i = 0;i<m;i++){
*(arr2+i)=i+m;
}
}
void array_concat(void *arr1, void *arr2, void *arr3, int n, int m,int size){
for(int i=0;i<n;i++){
memcpy((arr3+i),(arr1+i),size);
}
for(int i=0;i<m;i++){
memcpy((arr3+i+n),(arr2+i),size);
}
}
int main(int argc, char const *argv[])
{
int n=10;
int m=10;
float f1[n];
float f2[m];
array_float_fill(f1,f2,n,m);
printf("%f",*(f1+3));
float* f3 = malloc((n+m) * sizeof(float));
array_concat(f1,f2,f3,n,m,sizeof(float));
printf("%f",*(f3+3));
return 0;
}
我尝试使用for
循环将每个元素复制到新数组,因为该函数只会给我一个指向数组开头的指针。不知道为什么它不起作用。任何帮助和提示将不胜感激
答案 0 :(得分:4)
void*
指针算术... ...实际上不允许在标准C中使用.gcc允许它并假设基本操作数大小为1.因此它遵循
使用memcpy
时,您会将字节与索引混淆。
当(非标准地)将整数添加到void
指针时,整数的含义(在gcc中)是字节偏移量的含义。这与类型化指针不同,编译器会为您进行适当的缩放:
void *p;
int i;
p[i]; // This will be literally p+i after compiling on your compiler
但是例如:
float *p;
int i;
p[i]; // This will be p+i*sizeof(float) after compiling.
所以不是......
for(int i=0;i<n;i++){
memcpy((arr3+i),(arr1+i),size);
}
for(int i=0;i<m;i++){
memcpy((arr3+i+n),(arr2+i),size);
}
...你必须写(这仍然是编译器特定的):
for(int i=0;i<n;i++){
memcpy((arr3+i*size), (arr1+i*size), size);
}
for(int i=0;i<m;i++){
memcpy((arr3+i*size+n*size), (arr2+i*size), size);
}
......或符合标准:
for(int i=0;i<n;i++){
memcpy((char*)arr3+i*size, (char*)arr1+i*size, size);
}
for(int i=0;i<m;i++){
memcpy((char*)arr3+i*size+n*size, (char*)arr2+i*size, size);
}
通过转换为char*
,您可以强制执行1个字节(更确切地说,1个C字节)的基本操作数大小,这是您想要的concat函数的通用性质。
请注意,您可以将任意步幅传递给memcpy
,实际上并不需要循环;相反,只是做:
memcpy((char*)arr3, arr1, size*n);
memcpy((char*)arr3+n*size, arr2, size*m);
只有在你做算术时才需要转换。
答案 1 :(得分:3)
你不必在循环中记忆。如果你知道数组的大小和长度,你只需要两个:
void array_concat(void *arr1, void *arr2, void *arr3, int n, int m,int size)
{
memcpy( arr3 , arr1 , size * n ) ;
memcpy( ( char* )arr3+( size * n ) , arr2 , size * m ) ;
}
行( char* )arr3+( size * n )
给出了指向第一部分结尾的指针。
需要转换为char *因为指针算法不能用于void *,所以我们手动将指针递增到正确的偏移量。
例如( char* )arr3+( n )
不正确,因为底层类型是float。这就是为什么你传递float的大小然后使用它。
您的编译器似乎有一个扩展,允许您使用void *,因为它在使用指针算术时是一个char *。然后在这里错误地增加它:arr3+i
只是通过
sizeof的值(char),而不是sizeof(float)。
答案 2 :(得分:1)
您可以使用单个memcpy
复制整个数组。检查memcpy
的签名:
void *memcpy(void *dest, const void *src, size_t n);
它会将n
个连续字节从src
复制到dest
,就像听起来一样简单。数组是一个连续的内存块,因此您只需调用memcpy
即可复制整个数组。
我在下面的代码中解决了这个问题以及其他一些问题:
通过索引访问数组而不是执行指针运算,这很容易出错。
<强> Constness 强>
size_t
而不是int
用于大小和数组索引。请参阅 Why size_t matters 。
在复制之前传递输出缓冲区大小并检查它是个好习惯,以防止缓冲区溢出。
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void array_float_fill(float *arr1, float *arr2, size_t n, size_t m) {
for (size_t i = 0; i<n; i++) {
arr1[i] = i + n;
}
for (size_t i = 0; i<m; i++) {
arr2[i] = i + m;
}
}
void array_concat(
void *out_arr,
size_t out_arr_size,
const void *in_arr1,
size_t in_arr1_size,
const void *in_arr2,
size_t in_arr2_size)
{
const size_t total_size = in_arr1_size + in_arr2_size;
// BE AWARE that `assert` will be gone if you define `NDEBUG`
// (or compile with `-DNDEBUG`).
// This assertion guarantees we have enough space before copying.
assert(out_arr_size >= total_size);
memcpy(out_arr, in_arr1, in_arr1_size);
memcpy((char *)out_arr + in_arr1_size, in_arr2, in_arr2_size);
// The cast to `char *` above is important for portability.
// Arithmetic on a pointer to void is a GNU extension.
// See http://gcc.gnu.org/onlinedocs/gcc/Pointer-Arith.html
}
void dump_array(const char *name, float *array, size_t num_elems) {
printf("%s = ", name);
for (size_t i = 0; i < num_elems; i++) {
printf("%f ", array[i]);
}
printf("\n");
}
int main() {
const size_t n = 10;
const size_t m = 10;
float f1[n];
float f2[m];
array_float_fill(f1, f2, n, m);
const size_t f3_size = (n + m) * sizeof(float);
float *f3 = malloc(f3_size);
array_concat(f3, f3_size, f1, sizeof(f1), f2, sizeof(f2));
// Show the results
dump_array("f1", f1, n);
dump_array("f2", f2, m);
dump_array("f3", f3, n + m);
return 0;
}
答案 3 :(得分:0)
无法对void指针执行算术运算。由于void指针没有任何固定的数据类型,如int或float,因此它们不知道它们应该在算术运算时递增或递减的值。例如,当您递增整数指针时,每增加一个值就会自动增加4。类似地,每增加一个字符指针将递增1。在你的例子中,当memcpy操作试图将值从arr1复制到arr3时,它无法取消引用arr3,因此出现问题。通常,只要对void指针执行任何此类操作,首先需要取消引用它们。将其引用到浮动指针将起作用,见下文
memcpy(((float*)arr3+i),((float*)arr1+i),size);
memcpy(((float*)arr3+i+n),((float*)arr2+i),size);
答案 4 :(得分:-1)
尝试以下
void array_concat( const void *arr1, const void *arr2, void *arr3, int n, int m, int size )
{
memcpy( arr3, arr1, n * size );
memcpy( ( char * )arr3 + n * size, arr2, m * size );
}
以下是程序的外观
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void array_float_fill( float *arr1, float *arr2, size_t n, size_t m )
{
for ( size_t i = 0; i < n; i++ )
{
*( arr1 + i ) = i + n;
}
for ( size_t i = 0; i < m; i++ )
{
*( arr2 + i ) = i + m;
}
}
void array_concat( const void *arr1, const void *arr2, void *arr3,
size_t n, size_t m, size_t size )
{
memcpy( arr3, arr1, n * size );
memcpy( ( char * )arr3 + n * size, arr2, m * size );
}
int main( void )
{
size_t n = 10;
size_t m = 10;
float f1[n];
float f2[m];
array_float_fill( f1, f2, n, m );
printf( "%f\n",*( f1 + 3) );
float *f3 = malloc( ( n + m ) * sizeof( float ) );
array_concat( f1, f2, f3, n, m, sizeof( float ) );
printf( "%f\n", *( f3 + 3 ) );
free( f3 );
return 0;
}
输出
13.000000
13.000000
不要忘记释放动态分配的数组。此外,您还应该包含标头<string.h>
,其中memcpy
已声明。
考虑到这个主要宣言
int main(int argc, char const *argv[])
错了。 正确的声明看起来像
int main(int argc, char *argv[])