Author Topic: copying from an array of one size to an array of another  (Read 1648 times)

0 Members and 1 Guest are viewing this topic.

Online SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 17812
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
copying from an array of one size to an array of another
« on: January 31, 2022, 09:16:40 pm »
i need to do something like memcpy() but between a source and destination of different sizes.

So I have a character display. 4 lines, 20 characters per line. I have an array that contains the data on the display, I call it the display buffer. Into that I want to copy any one of a predefined page array. It makes things simpler later to call up the page as anther dimension of an array.

So I have display_buffer[4][20] (rows, chars) and display_pages[7][4][20] (pages, rows, chars). I have tried with my very basic skills of pointers and then tried memcpy(). This works only if I drop the page dimension from the source. Later I would of had languages too but clearly I may be barking up the wrong tree.

I was hoping to give a function a pointer to the start of one of the pages and cycle through the 80 characters copying them into the buffer.

An interrupt based display refresh routine puts the contents of the display_buffer array on the display so all I have to do is fill the buffer with what I want in the location I want it.
 

Offline jamesglanville

  • Contributor
  • Posts: 47
Re: copying from an array of one size to an array of another
« Reply #1 on: January 31, 2022, 09:22:00 pm »
Quote
memcpy(display_buffer, &display_pages, sizeof(display_buffer))

i is a variable giving the index of the page you want.

You need to pass addresses to memcpy, I’m guessing the missing & was the problem?
 

Offline jamesglanville

  • Contributor
  • Posts: 47
Re: copying from an array of one size to an array of another
« Reply #2 on: January 31, 2022, 09:24:40 pm »
I can’t make the formatting work.

For the source, you need & display_pages [  i  ]
 

Online SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 17812
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: copying from an array of one size to an array of another
« Reply #3 on: January 31, 2022, 09:48:16 pm »
Quote
memcpy(display_buffer, &display_pages, sizeof(display_buffer))

i is a variable giving the index of the page you want.

You need to pass addresses to memcpy, I’m guessing the missing & was the problem?

so if I use the 3 dimensional array start location in that with the & you think it will work? I'll try tomorrow, I don't look forward to 7 page sets in 7 languages as separate variables.
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 6227
  • Country: fi
    • My home page and email address
Re: copying from an array of one size to an array of another
« Reply #4 on: January 31, 2022, 10:07:14 pm »
So I have display_buffer[4][20] (rows, chars) and display_pages[7][4][20] (pages, rows, chars). I have tried with my very basic skills of pointers and then tried memcpy(). This works only if I drop the page dimension from the source. Later I would of had languages too but clearly I may be barking up the wrong tree.
Code: [Select]
memcpy(display_buffer, display_pages[page], sizeof display_buffer);
If you have languages, and sufficient memory, then
Code: [Select]
#define  NUM_LANGUAGES  3
#define  NUM_PAGES  7
#define  NUM_ROWS  4
#define  NUM_COLS  20

unsigned char  display_buffer[NUM_ROWS][NUM_COLS];

const unsigned char  display_pages[NUM_LANGUAGES][NUM_PAGES][NUM_ROWS][NUM_COLS];

void set_display(int lang, int page)
{
    if (lang >= 0 && lang < NUM_LANGUAGES && page >= 0 && page < NUM_PAGES)
        memcpy(display_buffer, display_pages[lang][page], sizeof display_buffer);
}
« Last Edit: January 31, 2022, 11:09:29 pm by Nominal Animal »
 

Online SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 17812
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: copying from an array of one size to an array of another
« Reply #5 on: January 31, 2022, 10:16:39 pm »
I'm not sure i follow. Yes I want to do the first bit. create an array as a constant that contains the lot, that way I don't put it all into RAM, I could but I don't want to splurge resources as I am at the start of working for this company starting coding my own stuff from scratch and I don't want a find myself limited on a project in the future because I am reusing crappy wasteful code I wrote.

Most of the text is fixed so if I want to change page I load the entire static base page then update the specific character locations that show runtime variables as they change.
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 6227
  • Country: fi
    • My home page and email address
Re: copying from an array of one size to an array of another
« Reply #6 on: January 31, 2022, 11:22:48 pm »
Right.  So, in addition to each page, you'll have some kind of list of variables displayed and how the values are formatted.

In any case, the core point is that if you have an array
    TYPE  name[N3][N2][N1];
then
    name[i3]
refers to the i3'th sub-array, TYPE [N2][N1].  Also,
    (void *)(name[i3]) == (void *)&(name[i3][0][0])

Similarly,
    name[i3][i2]
refers to the [i3][i2]'th sub-array, TYPE[N1], and
    (void *)(name[i3][i2]) == (void *)&(name[i3][i2][0])

So, if you have say
    const unsigned char  display_page[PAGES][4][20];
then
    display_page[0]
refers to a two-dimensional array of const unsigned char with dimensions [4][20].  Because memcpy() takes void *, referring to the sub-array is converted to a void pointer to its first element.  Thus,
    memcpy(destination, display_page[pagenum], sizeof display_page[0]);
copies the 80 bytes of page pagenum to destination.

The sizeof display_page[0] works, because display_page[0] refers to a [4][20] array of const unsigned char, and the sizeof operator only examines its type; no memory is ever accessed.

Indeed, if you have say struct somestruct *pointer; then (sizeof *pointer == sizeof (struct somestruct)), because the sizeof operator does not evaluate its argument, it only examines it for the type of the argument.  There is no problem even if pointer == NULL, because the operator does not cause pointer to be dereferenced.  More importantly,
Code: [Select]
    int  x = 4;
    printf("sizeof ++x = %zu\n", sizeof ++x);
    printf("x = %d\n", x);
will print x = 4 (and NOT x = 5), simply because sizeof is the special size-examining operator, and not a function-like thing.
« Last Edit: January 31, 2022, 11:35:29 pm by Nominal Animal »
 

Online SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 17812
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: copying from an array of one size to an array of another
« Reply #7 on: February 01, 2022, 08:08:42 am »
I'm sort of aware that using the name of an array with no index is a pointer to the first element so it sounds like you are talking about this same principle where leaving out sub array indexes means I am pointing to the start of the sub array that is listed like pages[page0] is a pointer to the start of pages[page0][row0][col0].
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 6227
  • Country: fi
    • My home page and email address
Re: copying from an array of one size to an array of another
« Reply #8 on: February 01, 2022, 08:29:58 am »
I'm sort of aware that using the name of an array with no index is a pointer to the first element so it sounds like you are talking about this same principle where leaving out sub array indexes means I am pointing to the start of the sub array that is listed like pages[page0] is a pointer to the start of pages[page0][row0][col0].
Yes, I think you got it.

Consider the following example C program:
Code: [Select]
#include <stdio.h>

#define  XSIZE 4
#define  YSIZE 4
#define  ZSIZE 4

void show_3d(const char *title, int map[ZSIZE][YSIZE][XSIZE])
{
    printf("%s:\n", title);
    for (int z = 0; z < ZSIZE; z++) {
        printf("  z = %d:\n", z);
        for (int y = 0; y < YSIZE; y++) {
            printf("    ");
            for (int x = 0; x < XSIZE; x++) {
                printf(" %3d", map[z][y][x]);
            }
            printf("\n");
        }
    }
    printf("\n");
}

void show_2d(const char *title, int map[YSIZE][XSIZE])
{
    printf("%s:\n", title);
    for (int y = 0; y < YSIZE; y++) {
        printf("    ");
        for (int x = 0; x < XSIZE; x++) {
            printf(" %3d", map[y][x]);
        }
        printf("\n");
    }
    printf("\n");
}

void show_1d(const char *title, int map[XSIZE])
{
    printf("%s:\n    ", title);
    for (int x = 0; x < XSIZE; x++) {
        printf(" %3d", map[x]);
    }
    printf("\n\n");
}

int main(void)
{
    int  map[ZSIZE][YSIZE][XSIZE];

    for (int z = 0; z < ZSIZE; z++) {
        for (int y = 0; y < YSIZE; y++) {
            for (int x = 0; x < XSIZE; x++) {
                map[z][y][x] = z*100 + y*10 + x;
            }
        }
    }

    show_3d("3D", map);
    show_2d("2D with z=0", map[0]);
    show_2d("2D with z=1", map[1]);
    show_1d("1D with z=2 and y=3", map[2][3]);
    show_1d("1D with z=3 and y=0", map[3][0]);

    return 0;
}
Writing and running tests like this with all error checking enabled (-Wall -Wextra -pedantic -std=c99) is an useful way to explore these things.

The output is
Code: [Select]
3D:
  z = 0:
       0   1   2   3
      10  11  12  13
      20  21  22  23
      30  31  32  33
  z = 1:
     100 101 102 103
     110 111 112 113
     120 121 122 123
     130 131 132 133
  z = 2:
     200 201 202 203
     210 211 212 213
     220 221 222 223
     230 231 232 233
  z = 3:
     300 301 302 303
     310 311 312 313
     320 321 322 323
     330 331 332 333

2D with z=0:
       0   1   2   3
      10  11  12  13
      20  21  22  23
      30  31  32  33

2D with z=1:
     100 101 102 103
     110 111 112 113
     120 121 122 123
     130 131 132 133

1D with z=2 and y=3:
     230 231 232 233

1D with z=3 and y=0:
     300 301 302 303
 
The following users thanked this post: rstofer, DiTBho

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 5890
  • Country: es
Re: copying from an array of one size to an array of another
« Reply #9 on: June 02, 2022, 03:10:33 am »
Sorry for the refloat, but wouldn't this do the job straight away?
I don't think it's UB, the compiler knows both src and dst are the same type, I use this approach often, never had any problem.
Code: [Select]
typedef struct{
  char d[4][20];
}dispbf_t;

dispbf_t display_buffer;
dispbf_t display_pages[7];

void store_page (){
  display_pages[0] = display_buffer;
  display_pages[1] = display_buffer;
}
void access_array(){
  display_buffer.d[0][0] = 0;
  display_pages[0].d[0][0] = 0;
}
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 8166
  • Country: fi
Re: copying from an array of one size to an array of another
« Reply #10 on: June 02, 2022, 06:43:05 am »
Yes! When you realize arrays can be inside structs, and struct objects are like any variables (copied by assignment, passed by value, returned from a function...) C suddenly seems to become a higher level language!

Just be aware of such high-level language traps: from simple assignment operation, it's hard to intuitively see it's a large copy operation. Some leave the typedef away so that they need to explicitly write the struct keyword, working as a reminder it's likely going to be more than just a few bytes.

Whenever you can force the compiler to inline a function call, you can pretty safely pass large structs by value, and return them, and compiler will optimize all the excess copying crap out. This makes C look pretty high-level, and code is readable.
« Last Edit: June 02, 2022, 06:45:07 am by Siwastaja »
 
The following users thanked this post: DavidAlfa

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 6227
  • Country: fi
    • My home page and email address
Re: copying from an array of one size to an array of another
« Reply #11 on: June 02, 2022, 08:27:42 am »
(My point above was that one can avoid the copy operation completely.)
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 5890
  • Country: es
Re: copying from an array of one size to an array of another
« Reply #12 on: June 02, 2022, 09:30:22 am »
AFAIK, the compiler runs a memcpy under the hood when copying structs.
I guess it'll made inline optimizations for small data.
Of course, that's not a simple int copy, but you must know what you're doing.
I like it over memcpy or other methods, gives very compact and neat code, also you don't have to think about addressing, size, etc...
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14431
  • Country: fr
Re: copying from an array of one size to an array of another
« Reply #13 on: June 03, 2022, 06:30:56 pm »
AFAIK, the compiler runs a memcpy under the hood when copying structs.
I guess it'll made inline optimizations for small data.

Yes, just like memcpy itself.

Of course, that's not a simple int copy, but you must know what you're doing.
I like it over memcpy or other methods, gives very compact and neat code, also you don't have to think about addressing, size, etc...

Yes. It makes manipulating your data higher-level instead of a mix of high- and low-level that is pretty common in C.
Likewise, for zero'ing out a whole struct (which can contain anything you want including arrays) outside of initialization, you can use C99+ compound literals.
Like in your example:
Code: [Select]
display_buffer = (dispbf_t){ 0 };
It's higher-level than using memset().
 
The following users thanked this post: DavidAlfa


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf