Home > Software design >  Multi-Dimensional Arrays with Char / pointer Issues Writing to Curses
Multi-Dimensional Arrays with Char / pointer Issues Writing to Curses

Time:01-12

Newbie C programmer (experienced in other high level languages) and I'm still struggling to get used to arrays, pointers vs strings etc.

This project is recreating something I did in python. I am storing a character set (7 lines high by 6 wide) in an array. The array is multi-dimensional to store all the lines of all the characters referenced by their corresponding ascii code - array structure: font[ascii_code][line]. See code below for clarity.

The main loop will read one character from the message, look up it's corresponding ascii code in the font array and write out a column at a time to another array which is sort of a matrix of all screen positions. That matrix array then gets written to the screen with curses. Then we shift all cols of the matrix to the left and loop again. This effectively creating a leftward scroll text. Once we finish all 6 cols of a character from the font array we increment the message position, get the next message character and loop again.

My issues (I am sure because I am still learning the intricate ways of c programming):

I get an incredible amount of 'integer from pointer without a cast' errors which I believe is to do with referencing a string rather than a pointer to a string, but I'm struggling to understand this. I have been putting & in front of array references - it seems to sometimes work but not others.

I also don't understand why a declaration like

char cur_char = ' '; 

works fine but this does not:

char msg = "This is a message";

but this does:

char msg[] = "This is a message";

I read that I should use single quotes for a single character and double quotes for a string. I understand that chars are really arrays of ascii values but why it's necessary to declare with the brackets I don't really understand.

Again calling the curses function like this:

mvaddch(1, 74, " ");

gets me an 'integer from pointer' error. I was hoping to draw a space at row 1 col 74. If this function expects a pointer rather than a string, does that mean it's necessary to store a space in a char and then pass the pointer of that char to the function? I'm trying to figure out the proper approach here.

Finally, I am just after some guidance from more experienced c programmers as to a logical approach to this. Maybe storing all these strings in a large array is not the way to do it. Is it possible (practical) to put this character set in memory and reference it that way?

Any suggestions, tips and advice, gratefully and humbly accepted. Appreciate your eyeballs and I am determined to master this language!

Bonus round Originally I tried loading in my character set array from a function in a header file so I wouldn't have all these ugly data lines in the main c file. Gave up because I couldn't pass arrays back as a function return value. I am sure there's a better way. How would you split it out?

Here's the code: Still getting errors on:

mvaddch(l, m, scr_matrix[l][m]); // makes integer from pointer error; 
strcpy(scr_matrix[l][m], &scr_matrix[l][m   1]); // incompatible pointer type

Here is a test version of my code. Put comments in for clarity.

#include <curses.h>
#include <unistd.h> // For sleep()
#include <string.h> // For strlen()
#include <stdlib.h> // For malloc()

int main(int argc, char* argv[])
{
    // Let's initialise constants and set some configs
    char msg[] = "XYZ";
    int msg_length;
    int i, j, k, l, m;
    int msg_pos = 0;
    int char_pos = 0;
    char cur_char = ' ';

    // Array to make a matrix that we will draw to screen with curses
    char scr_matrix[7][76][2];  // Our lines (7) and cols (76) positions in an array

    // Lets just initalise all the array elements to contain spaces
    for (i = 0; i < 14; i  ) {
      for (j = 0; j < 75; j  ) {
        strcpy(scr_matrix[i][j], " "); //Have to use strcpy because can't set element
      }
    }

    // char font array to hold our char set
    char font2[100][7][7];  // 100 chars, 7 tall by 6 wide (  /0 makes 7)

    // Set array elements - first element correspond to char ascii code
    // glyphs are 7 lines tall by 6 wide
    // Use strcpy because cannot directly set elements?

    strcpy(font2[88][0], "@@  @@");
    strcpy(font2[88][1], "@@  @@");
    strcpy(font2[88][2], " @@@@ ");
    strcpy(font2[88][3], "  @@  ");
    strcpy(font2[88][4], " @@@@ ");
    strcpy(font2[88][5], "@@  @@");
    strcpy(font2[88][6], "@@  @@");

    strcpy(font2[89][0], "@@  @@");
    strcpy(font2[89][1], "@@  @@");
    strcpy(font2[89][2], " @@@@ ");
    strcpy(font2[89][3], " @@@@ ");
    strcpy(font2[89][4], "  @@  ");
    strcpy(font2[89][5], "  @@  ");
    strcpy(font2[89][6], "  @@  ");

    strcpy(font2[90][0], "@@@@@@");
    strcpy(font2[90][1], "@@@@@@");
    strcpy(font2[90][2], "   @@ ");
    strcpy(font2[90][3], "  @@  ");
    strcpy(font2[90][4], " @@   ");
    strcpy(font2[90][5], "@@@@@@");
    strcpy(font2[90][6], "@@@@@@");

    // Get msg length
    msg_length = strlen(msg);

    // Initialize screen for curses
    initscr();
    // Hide the cursor with curses
    curs_set(0);

    for (i = 0; i < msg_length; i  ) {

      cur_char = msg[msg_pos]; // keep track of which char from msg we are working on

      // Loop for 6 cols - 6 for glyph width
      for (j = 0; j < 7; j  ) {
        clear(); // Clear the screen with curses

        // Loop for 7 lines - writing 1 char of the glyph to the matrix
        for (k = 0; k < 7; k  ) {
          // cpy the character from font array into the matrix array
          strcpy(scr_matrix[k][74], &font2[cur_char][k][j]);
        }

        // Now add all matrix positions to the screen with curses mvaddch
        // Loops through all positions in scroll area
        for (l = 0; l < 7; l  ) {
          for (m = 0; m < 75; m  ) {
            mvaddch(l, m, scr_matrix[l][m]);  // add to screen with curses
            // now shift this character in the matrix over by -1 col so it shifts left
            strcpy(scr_matrix[l][m], &scr_matrix[l][m   1]);
          }
        }
        // Now draw the screen as built by curses with mvaddch
        refresh();
        // Wait a bit - pause for timing purpose
        usleep(80000);
      }  // Back to top of loop for the next col

      // Finished the glyph so add a col of spaces for kerning between letters
      for (l = 0; l < 7; l  ) {
        mvaddch(l, 74, " ");
        refresh();
        usleep(80000);
      }
      msg_pos  ;
    }

    // Clean up our curses screen
    endwin();

    return 0;
}


CodePudding user response:

explanation

  char cur_char = ' '; 

works fine becuase '<char>' is a single (8 bit) character literal. char is a data type that stores an 8-bit character

This doesnt work

 char msg = "This is a message";

because char only holds one character.

Sidebar: character strings in c:-

a character string in c is an contiguous array of 8-bit chars follows by a byte of 0

so this "Hello" is stored in memory as

 x48x65x6cx6cx6fx00
  H  e  l  l  o 

OK so what this

 char msg[] = "Hello";

does is creates a 6 (note the 1 for the 0) byte array on the stack and loads the letters Hello into it and adds the 0.

this does something quite different

 char *msg = "Hello";

this creates a 6 byte character array as a literal (usualy in the code segment) and the creates a pointer of the stack (called msg) and sets it to point at that literal

Hope this helps.

CodePudding user response:

The problem comes from the fact that C was basically crated without type safety and types checks were added later on, when some convinience syntax was alredy in place.

The convinience feature is that the name of an array can be used as a pointer to the first element if the indexing is left away.

char array[10];
char two_dim_array[10][20];

char *charpointer;

charpointer = array;     /* leaving the index away, so pointer to first element */
charpointer = &array[0]; /* basically the same */

charpointer = two_dim_array[3]; /* is short for */
charpointer = &two_dim_array[3][0];  /* this */

But if you use an array variable without index in sizeof or the address operator the compiler still knows it's an array.

char array[10];
char two_dim_array[10][20];

int size;
char *charpointer;

size = sizeof(array);     /* 10 */
size = sizeof(two_dim_array[3]); /* 20 */

charpointer = &two_dim_array[10]; /* wrong pointer type, address of array of 20 char */

To your Errors from the compiler:

mvaddch(l, m, scr_matrix[l][m]); // makes integer from pointer error;

As scr_matrix is declared as char scr_matrix[7][76][2];

scr_matrix[l][m] is a pointer to the fist byte of the string, of the lowest level array. The Compiler complains as mvaddch expects the integer code of the character scr_matrix[l][m][0] would be fine.

strcpy(scr_matrix[l][m], &scr_matrix[l][m 1]); // incompatible pointer type

Here the second parameter is &scr_matrix[l][m 1] the address of an array of 2 charaters. Expected is a pointer to a character scr_matrix[l][m 1] would be fine.

  • Related