I have the following arrays:
int A[] = {0,1,1,1,1, 1,0,1,0,0, 0,1,1,1,1};
int B[] = {1,1,1,1,1, 1,0,1,0,1, 0,1,0,1,0};
int C[] = {0,1,1,1,0, 1,0,0,0,1, 1,0,0,0,1};
//etc... for all letters of the alphabet
And a function that prints the letters on a 5x3 LED matrix:
void printLetter(int letter[])
I have a string of letters:
char word[] = "STACKOVERFLOW";
and I want to pass each character of the string to the printLetter function.
I tried:
int n = sizeof(word);
for (int i = 0; i < n-1; i++) {
printLetter(word[i]);
}
But I get the following error: invalid conversion from 'char' to 'int*'
What should i be doing?
Thanks!!
Behind the parameter type error there is a deeper issue: you lack the mapping between a char and the corresponding int[].
Redefining printLetter as
void printLetter(char letter)
satisfies the compiler, but doesn't solve your problem per se. Whether inside or outside printLetter, you need to get the corresponding int[] for a given char.
A simple brute-force way to achieve this would be to use a switch, but a better way is to use a second array, i.e. something like this:
void printLetter(char letter) {
static int* charToMatrix[] = { A, B, C, ... };
int* matrixToPrint = charToMatrix[letter - 'A'];
// print the matrix
}
Note that this is an example - I don't have access to a C compiler right now, so I can't guarantee it works straight away, but hopefully it illustrates the point well enough. It also lacks bounds checking, so it accesses memory in strange random places, possibly resulting in a crash, if you attempt to print an "unknown" character.
This solution is supposed to work for the uppercase letters; if you need to print lowercase letters or other characters as well, you might prefer going with an array of 256 elements, where only the elements at indexes corresponding to the "known" matrices are filled, and the rest is set to NULL.
You cannot so easly transform the 'a' from "stackoverflow" to the A - the array of ints. You can define all the arrays that represent a letter in one single letter and get them by the convertion of your letter to int.
What you need to do is convert from a character to one of your arrays. So when you have the letter 'A', you'll want to use array A. The easiest way to do this is via lookup table.
int *lookup[256]; // assuming ASCII
memset(lookup, 0, sizeof(lookup));
lookup['A'] = A;
lookup['B'] = B;
...
Then when you have a character, you can get the proper array:
void printletter(char c);
{
int *data = lookup((unsigned char)c);
// In case you get a letter that you don't know how to display
if (data != NULL)
{
// display with data
}
}
Instead of building up your array at runtime, you can also build up your array at compile time although it will be a bit harder as you will need to manually put in NULL pointers.
int *lookup[256] = {
NULL, // you need a total of 65 NULL's
NULL,
...
A, // so this is at the correct position
B,
C,
...
};
The function is declared as void printLetter(int letter[]), which means it takes a pointer to an array of ints. On the other hand, word is an array of chars, and word[i] is a char, which is not at all the right type. If printLetter() is really just supposed to print a single character, you should change its argument to be a char.
void printLetter(int letter[])
should be
void printLetter(char letter)
Because: word is a char[] word[i] is a character.
Related
I have not programmed in C in a long time. I am forgetting some fundamentals due to programming in JavaScript for so long, and would like some guidance.
I am making a program to display text on a LED matrix. Each character is represented by a series of 8 digit binary codes which represent columns of pixels. The idea is that for each character in a phrase, the code will fetch the relevant codes for that character and push them into a larger array.
The issue I am having is with passing / indexing an array filled with sub-arrays. When I try to run this code I get the error "invalid types 'int[int]' for array subscript".
How can I achieve the functionality I intend to? Here is my code.
int A[] = {01111111,10010000,10010000,10010000,01111111,00000000};
int B[] = {11111111,10010001,10010001,10010001,01101110,00000000};
int Space[] = {00000000,00000000};
char alphabet[] = "AB ";
int alphabetB[3] = {A,B,Space};
char phrase[] = "AB BAA";
int getLetterIndex(char letter,char alphabet[]){
for(int index; index < strlen(alphabet); index++){
if(alphabet[index] == letter){
return index;
}
}
}
int writePhrase(char phrase[],char alphabet[], int alphabetB[]){
int phraseB[]={};
int pos = 0;
for(int charIndex = 0; charIndex < strlen(phrase); charIndex++){
int index = getLetterIndex(letter,alphabet);
for(int colIndex = 0; colIndex < sizeof(alphabetB[index]); colIndex++){
phraseB[pos] = alphabetB[index][colIndex];
pos++;
}
}
return phraseB;
}
writePhrase(phrase,alphabet,alphabetB);
Thank you!
Problematic line in your code:
int A[] = {01111111,10010000,10010000,10010000,01111111,00000000};
Wrong type of array, int is 2 byte long. You probably want array of bytes. Octal and decimal constant for assign byte. Replace with char A[] = {0x7f, 0x90, 0x90, 0x7f, 0x00};
int alphabetB[3] = {A,B,Space};
alphabetB isn't two dimensional array. It is array of int. A is address of array A not array as whole object. It is same as expression &A[0] = address of first element. Replace as char* alphabetB[3] = {A,B,Space};
Function getLetterIndex don't return error indication if letter is not in alphabet.
int phraseB[]={};
C does not support arrays with a dynamic number of elements. You must define size of array, or initializer list. Also you can not create array as local variable. Local variables is allocated on the stack and it is released at end of the function. Btw function not return array, but address of phraseB on the stack
int index = getLetterIndex(letter,alphabet);
letter is not defined. Probably you wont pass char from phrase like int index = getLetterIndex(phrase[charIndex],alphabet);
Last problem is copy loop. alphabetB isn't two dimensional array. You can't do this assigment phraseB[pos] = alphabetB[index][colIndex];
Also here is posibility rewriting stack frame and program hang up.
Look here, how to do matrix control in C.
maxtrix control example
I just started learning C language and I need some help with a program. Here is the code.
Questions:
What is this? customerData[NUM_FIELDS][FIELD_LENGTH];
Is it a char 2D array?
How do you input data into the array? fgetC, putchar, getchar ?
#include <stdio.h> #include <string.h> #include <stdlib.h>
#define INPUT_LENGTH 128
#define FIELD_LENGTH 30
#define NUM_FIELDS 9
int main()
{
FILE *data=NULL;
char input[INPUT_LENGTH];
char customerData[NUM_FIELDS][FIELD_LENGTH];
int element=0;
char *next;
char ch;
data= fopen("data.txt","r");
if(data!=NULL)
{
//token=strtok(input,"|");
/*while loop will go through line by line and stored it in an input array*/
while(fgets(input,INPUT_LENGTH,data)!= NULL)
{
next=strtok(input,"|");
while(next!=NULL)
{
//ch=getchar()
//>probably a get char for ch
strcpy(next,customerData[element][strlen(next)]);
/*need to put the values into customer data one by one*/
printf("%s\n",next);
//element+=1;
next=strtok(NULL,"|");
}
//element=0;
}
printf("program is done\n");
}
fclose(data);
return 0;
}
In general, "help me with my code" questions are off-topic on Stack Overflow. In order to keep the question on-topic, I'm going to focus only on the question of how to access 2D char arrays.
Yes, this is a 2D char array. Or, put another way, it's an array with NUM_FIELDS elements, where each element of the array is a char array with FIELD_LENGTH elements.
There are loads of ways to insert data into a 2D char array, but there are probably two I've encountered most often. Which one you choose to use will depend on how you want to think of this array.
Option 1: A 2D array of single chars
The first way to think about this variable is simply as a 2D array of chars - a grid of elements that you can access. Here, you can simply input values using the normal assignment operator. You'll want to make sure that your indexes are in range, or you'll start accessing invalid memory.
//Set a known element that's definitely in range
customerData[1][2] = 'A';
//Loop through all the elements
for(int ii = 0; ii < NUM_FIELDS; ii++)
{
for (int jj = 0; jj < FIELD_LENGTH; jj++)
{
customerData[i][j] = 'B';
}
}
//Set an element from variables
char nextInput = getNextCharFromInput();
if(x < NUM_FIELD && y < FIELD_LENGTH)
{
customerData[x][y] = nextInput;
}
//Bad. This could corrupt memory
customerData[100][60] = 'X';
//Risky without check. How do you know x and y are in range?
cusomterData[x][y] = 'X';
You could certainly write your code by assigning these elements on character at a time. However, the broader context of your program heavily implies to me that the next option is better.
Option 2: A 1D array of fixed-length strings
In C, a "string" is simply an array of chars. So another way to look at this variable (and the one that makes the most sense for this program) is to treat it as a 1D array of length NUM_FIELDS, where each element is a string of length FIELD_LENGTH.
Looking at this this way, you can start using the C string functions to input data into the array, rather than needing to deal character by character. As before, you still need to be careful of lengths so that you don't go off the end of the strings.
Also be aware that all array decay into pointers, so char* is also a string (just of unknown length).
//Set a specific field to a known string, which is short enough to fit
strcpy(customerData[2], "date");
//Loop through all fields and wipe their data
for(int ii = 0; ii < NUM_FIELDS; ii++)
{
memset(customerData[ii], 0, FIELD_LENGTH);
}
//Set field based on variables
if(x < NUM_FIELDS)
{
//Will truncate next if it is too long
strncpy(customerData[x], next, FIELD_LENGTH);
//Will not input anything if field is too long
if(strlen(next) < FIELD_LENGTH)
{
strcpy(customerData[x], next);
}
}
//Bad. Could corrupt memory
strcpy(customerData[100], "date");
strcpy(customerData[1], "this string is definitely much longer than FIELD_LENGTH");
//Risky. Without a check, how do you know either variable in in range?
strcpy(customerData[x], next);
getchar and fgetC both deal with reading characters, from stdout and a file respectively, so can't be used to put data into a variable. putchar does deal with put character into things, but only stdout, so can't be used here.
I'm trying to convert a decimal value into a string. I use the STM32CubeIDE IDE but am getting an error like 'Invalid binary operator'. I'm able to set &n to the decimal value 3695. I need to convert that into a string. How would I do that?
void main()
{
uint8_t TxArr;
uint16_t Data;
int a[10];
int i;
while (1)
{
HAL_I2C_Master_Transmit(&hi2c1,0x16, &TxArr, 1, 1000);
HAL_I2C_Master_Receive(&hi2c1, 0x17, &Data, 2, 1000);
for(i=0;i<4;i++)
{
a[i]=Data%10+0x30; //value in Data is 3695.
Data=Data/10;
HAL_UART_Transmit(&huart3, a[i], 11, 100);
HAL_Delay(300);
}
}
The error is produced by:
n = n / 10;
What this would do if n was a pointer (int* n) is that it would repoint n to a location one tenth the original number. You will need to begin using normal array operators if you want your code to work properly.
The second problem you have is the following:
You declare n as a array of 10 integers of type and with int.
int n[10];
Then in your for loop you try to do this:
n > 0;
This is an invalid operation as n wil decay into a pointer and as such the address of your array is compared to 0. This will always evaluate as TRUE!
A good way to convert a integer to a string (char array) is this answer.
In your sitaution that would be
int yourToBeConvertedNumber;
char str[INT_MAX]; // or any other reasonable upper bound you have set for the input data.
snprintf(str, sizeof(str), "%d", yourToBeConvertedNumber);
Generally speaking, to convert an integer to a string, you can use the sprintf function. It should be available in newliband even newlib-nano standard C libraries.
However my guess here is that you have an array of integers where each element is a number between 0 and 9 ?
If this is true you have several issues: you seem to handle the variable n like an integer and not an address. Also your string should be one element longer and composed of chars.
You may do something like this:
char a[11];
for(i=0;i<10;i++)
{
a[i]=n[i]%10 +'0';
}
a[11]='\0';
Note I'm using C not C++. I'm working on a program that will take a 2d-array and count the numbers of non-spaces in a subarray. Such as lines[0][i] <-- iterating over line[0][0] - line[0][n]. However, I'm having difficulty getting the function to accept the 2d-array.
Here is my code:
pScore[0]=letters(pLines, 0);
This is the actual function. pScore[] is another array, but a 1d one. pLines is a 4 by 200 2d-array.
int letters(char line[][], int row)
{
int i = 0;
int n = n;
int results = 0;
for( i = 0; i < (sizeof(line)/sizeof(line[0])); i++ )
{
if( !isspace(line[row][i]) )
results++;
}
return results;
}
When I do this it gives me "formal parameter number 1 is not complete". If I remove the second [] from it, the code runs but gives the worng number of non-space characters.
Taking from the comments above, and your function parameter list:
int letters(char line[][], int row)
You violate one primary tenant of passing a 2D array to a function. Specifically, you must always provide the number of columns contained in the array. e.g.
int letters(char line[][5], int row)
char line[][5] is an appropriate parameter. However, whenever you pass an array as a function parameter, the first level of indirection is converted to a pointer. (you will often here this referred to as "pointer-decay", though that is a bit of a misnomer). Therefore a proper declaration that makes this clear is:
int letters(char (*line)[5], int row)
line, after conversion, is a pointer-to-an-array of 5-int. While you can pass the array as line[][5], that is not nearly as informative as (*line)[5]. Let me know if you have any questions.
Numbers Instead of Characters
It is hard to tell what is going on without seeing the remainder of your code. However, I suspect that you are confusing the numerical value and the ASCII character value for the contents of your array. (e.g. character '0' = decimal 48 (0x30 (hex), '1' = 49, 'a' = 97, etc..). See ASCIItable.com
You you pass an array to a function it decays to a pointer. That means char line[][] should really by char (*line)[SIZE_OF_SECOND_ARRAY].
It also means the sizeof trick will not work, as doing sizeof on the pointer line will just return the size of the pointer and not what it points to, you need to explicitly pass the size as an argument to the function.
You need tell function the number of columns of 2d array. Here may help you.
I am not sure if the following statement works with you
for( i = 0; i < (sizeof(line)/sizeof(line[0])); i++ )
where sizeof(line) will be 4 or something like that depends on your platform because "line" is a pointer and you get the size of pointer itself.
Correct me if I am wrong.
In this case, you should pass column number as row's.
Can I declare an int array, then initialize it with chars? I'm trying to print out the state of a game after each move, therefore initially the array will be full of chars, then each move an entry will be updated to an int.
I think the answer is yes, this is permitted and will work because an int is 32 bits and a char is 8 bits. I suppose that each of the chars will be offset by 24 bits in memory from each other, since the address of the n+1'th position in the array will be n+32 bits and a char will only make use of the first 8.
It's not a homework question, just something that came up while I was working on homework. Maybe I'm completely wrong and it won't even compile the way I've set everything up?
EDIT: I don't have to represent them in a single array, as per the title of this post. I just couldn't think of an easier way to do it.
You can also make an array of unions, where each element is a union of either char or int. That way you can avoid having to do some type-casting to treat one as the other and you don't need to worry about the sizes of things.
int and char are numeric types and char is guaranteed smaller than int (therefore supplying a char where an int is expected is safe), so in a nutshell yes you can do that.
Yes it would work, because a char is implicitly convertible to an int.
"I think the answer is yes, this is permitted and will work because an int is 32 bits and a char is 8 bits." this is wrong, an int is not always 32 bits. Also, sizeof(char) is 1, but not necessarily 8 bits.
As explained, char is an int compatible type.
From your explanation, you might initially start with an array of int who's values are char, Then as the game progresses, the char values will no longer be relevant, and become int values. Yes?
IMHO the problem is not putting char into an int, that works and is built into the language.
IMHO using a union to allow the same piece of space to be used to store either type, helps but is not important. Unless you are using an amazingly small microcontroller, the saving in space is not likely relevant.
I can understand why you might want to make it easy to write out the board, but I think that is a tiny part of writing a game, and it is best to keep things simple for the rest of the game, rather than focus on the first few lines of code.
Let's think about the program; consider how to print the board.
At the start it could be:
for (int i=0; i<states; ++i) {
printf("%c ", game_state[i]);
}
Then as the game progresses, some of those values will be int.
The issue to consider is "which format is needed to print the value in the 'cell'?".
The %c format prints a single char.
I presume you would like to see the int values printed differently from ordinary printed characters? For example, you want to see the int values as integers, i.e. strings of decimal (or hex) digits? That needs a '%d' format.
On my Mac I did this:
#include <stdio.h>
#define MAX_STATE (90)
int main (int argc, const char * argv[]) {
int game_state[MAX_STATE];
int state;
int states;
for (states=0; states<MAX_STATE; ++states) {
game_state[states] = states+256+32;
}
for (int i=0; i<states; ++i) {
printf("%c ", game_state[i]);
}
return 0;
}
The expression states+256+32 guarantees the output character codes are not ASCII, or even ISO-8859-1 and they are not control codes. They are just integers. The output is:
! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? # A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y
I think you'd like the original character to be printed (no data conversion) when the value is the initial character (%c format), but you do want to see data conversion, from a binary number to a string of digit-characters (%d or a relative format). Yes?
So how would the program tell which is which?
You could ensure the int values are not characters (as my program did). Typically, this become a pain, because you are restricted on values, and end up using funny expressions everywhere else just to make that one job easier.
I think it is easier to use a flag which says "the value is still a char" or "the value is an int"
The small saving of space from using a union is rarely worth while, and their are advantages to having the initial state and the current move available.
So I think you end up with something like:
#include <stdio.h>
#define MAX_STATE (90)
int main (int argc, const char * argv[]) {
struct GAME { int cell_state; int move; char start_value } game_state[MAX_STATE];
enum CELL_STATE_ENUM { start_cell, move_cell };
int state;
int states;
for (states=0; (state=getchar())!= EOF && states<MAX_STATE; ++states) {
game_state[states].start_value = state;
game_state[states].cell_state = start_cell;
}
// should be some error checking ...
// ... make some moves ... this is nonsense but shows an idea
for (int i=0; i<states; ++i ) {
if (can_make_move(i)) {
game_state[states].cell_state = move_cell;
game_state[states].move = new_move(i);
}
}
// print the board
for (int i=0; i<states; ++i) {
if (game_state[i].cell_state == start_cell) {
printf("'%c' ", game_state[i].start_value);
} else if (game_state[i].cell_state == move_cell) {
printf("%d ", game_state[i].move);
} else {
fprintf(stderr, "Error, the state of the cell is broken ...\n");
}
}
return 0;
}
The move can be any convenient value, there is nothing to complicate the rest of the program.
Your intent can be made a little more clear my using int8_t or uint8_t from the stdint.h header. This way you say "I'm using a eight bit integer, and I intend for it to be a number."
It's possible and very simple. Here is an example:
int main()
{
// int array initialized with chars
int arr[5] = {'A', 'B', 'C', 'D', 'E'};
int i; // loop counter
for (i = 0; i < 5; i++) {
printf("Element %d id %d/%c\n", i, arr[i], arr[i]);
}
return 0;
}
The output is:
Element 0 is 65/A
Element 1 is 66/B
Element 2 is 67/C
Element 3 is 68/D
Element 4 is 69/E