return char array

Come on - read the C or C++ language definition

In a comma expression E1, E2, the expression E1 is evaluated, its result is discarded, and its side effects are completed before evaluation of the expression E2 begins. The type, value, and value category of the result of the comma expression are exactly the type, value, and value category of the second operand, E2.

So said simply - when you use the comma operator outside a function to separate parameters, it means evaluate each element separately and it returns whatever the last one evaluated to.

Try this code:

int a, b, c;

void setup() {
  Serial.begin(115200);
  a = 1, 2, 3; Serial.println(a); // prints 1 because the comma operator has lower precedence than = 
  a = (1, 2, 3); Serial.println(a); // prints 3
  a = ((b = 8), (c = 3)); Serial.println(a); // initializes  b with 8, c with 3, returns the value of (c=3) thus a with 3,
  a = ((b = 2), (c = 3), 5); Serial.println(a); // initializes  b with 2, c with 3 and a with 5
}

void loop() {}

So for your codeC[0,1,2]=data(A);
this is what the compiler does with this:

On the left side: evaluate "0,1,2" --> based on the above that is 2 so you do C[2] = something

the something is whatever is returned by the right side of the = operator, here a function call, cast into the format of what C holds (here char)

if we look at your function definition [color=blue]char[/color] data(byte D){ you are making a promise to the compiler that this function will returns a char... but in the code you do return B; doesn't that sounds weird?? The compiler will complain that you are a liar and that you did not keep your promise and give you a warning!

[color=orange]warning: invalid conversion from 'char*' to 'char' [-fpermissive] return B;[/color]

if you ignore that warning the function will convert the value of B - the pointer to (which is the address of) the B array memory space - to a char by taking the least significant byte of that address. if the address is 0x12[color=blue]34[/color] then it will only return

0x34

Try this code:

char A[3] = {'1', '2', '3'};
char B[3] = {'1', '2', '3'};

void setup() {
  Serial.begin(115200);
  A[0, 1, 2] = 'X'; 
  Serial.print(A[0]); Serial.print("-"); Serial.print(A[1]); Serial.print("-"); Serial.println(A[2]);
  
  A[0, 1, 2] = data('X'); 
  Serial.print(A[0]); Serial.print("-"); Serial.print(A[1]); Serial.print("-[0x"); Serial.print(A[2], HEX); Serial.println("]");
}

char data(byte D) { //function
  B[0] = 'a';
  B[1] = 'b';
  B[2] = 'c';
  Serial.print("Address of B=0x");Serial.println((int)B,HEX); // address of the array in memory will be 0x100 most likely
  return B;
}
void loop() {}

will get a warning at the compilation and it will print on the console

1-2-[color=red]X[/color]
Address of B=0x1[color=blue]00[/color]
1-2-[color=blue]0x0[/color]

so you can see that

A[0, 1, 2] = 'X'; is the same as A[2] = 'X';
and
A[0, 1, 2] = data('X'); is the same (ignoring the warning) A[2] = low part of the address of B;

the right way to copy - B into array C (for standard types) is

for (int i = 0; i < 3; i++) C[i] = B[i];// 3 being the nb of items of our array here

We can do different in C++ but I suggest you stick to the for loop for the time being and really really go back to basics of programming. learn the language, the syntax and the grammar otherwise it's like speaking a foreign language without knowing what you are saying, no-one will understand what you say...