Can an array in C be indexed by a character? - c

void shifttable(char p[]) {
int i, j, m;
m = strlen(p);
for (i = 0; i < MAX; i++)
t[i] = m;
for (j = 0; j < m - 1; j++)
t[p[j]] = m - 1 - j;
}
I think, t[p[j]]=m-1-j; part, is indexed using a character.
Can someone explain me how its actually working?

The array indexing operator is treated as *(arr + index).
When one operand of the binary + operator is a pointer, the other operand must be an integral type.
char is an integral type.
Hence,
t[p[j]] = m-1-j;
is a legal statement.

The character will be converted to equivalent ascii value and it acts as an index to an array. Below piece of code gives you an example,
void main()
{
int a[10];
a['\t'] = 10;
printf("%d\n",a[9]);
}
Output: 10
Here ascii value of tab is 9 so a[9] will be 10. Please refer https://www.asciitable.com/ for decimal and hex equivalent of character.
Hope it helps you.

p[j] returns the ascii code of j-th character in p[], which is used later as index in t (the ascii code is extended to int by the compiler, see integer promotions).

char is an integral type. It can be used as an index value for the [] operator. Note however that t['0'] is not the same element as t[0]. The value of '0' depends on the encoding used on the platform. Most environments use ASCII for the source and execution character sets, where '0' has the value 48.
Indexing through character values is useful for many algorithms, especially searching and word matching. Typical implementations of the functions in <ctype.h> use arrays of 257 entries (or sometimes 384 entries for safety) where the function argument is used as an index.
Yet there is a major problem in using char values an index variables: the char type can be signed or unsigned by default, so the range of its values can encompass negative values. In the code fragment, if t is an array or a pointer to the beginning of an array, any character in p with a negative value will cause an access outside the boundaries of the array, which has undefined behavior.
It is advisable to raise the warning level so the compiler diagnoses such uses that are well hidden potential bugs. Use gcc -Wall or clang -Weverything.
To avoid this potential problem, the code should be modified this way:
#define MAX 256
int t[MAX];
void shifttable(char p[]) {
int i, j, m;
m = strlen(p);
for (i = 0; i < MAX; i++)
t[i] = m;
for (j = 0; j < m - 1; j++)
t[(unsigned char)p[j]] = m - 1 - j;
}
Note also that i, j, m and the t array should have type size_t to handle strings longer than INT_MAX.

Related

Maximum product of 13 adjacent numbers of a 1000-digit number

I have to find the largest product of 13 adjacent numbers of a 1000-digit number below. My code for the problem is as follows:
#include <stdio.h>
int main()
{
char arr[1000] =
"731671765313306249192251196744265747423553491949349698352031277450"
"632623957831801698480186947885184385861560789112949495459501737958"
"331952853208805511125406987471585238630507156932909632952274430435"
"576689664895044524452316173185640309871112172238311362229893423380"
"308135336276614282806444486645238749303589072962904915604407723907"
"138105158593079608667017242712188399879790879227492190169972088809"
"377665727333001053367881220235421809751254540594752243525849077116"
"705560136048395864467063244157221553975369781797784617406495514929"
"086256932197846862248283972241375657056057490261407972968652414535"
"100474821663704844031998900088952434506585412275886668811642717147"
"992444292823086346567481391912316282458617866458359124566529476545"
"682848912883142607690042242190226710556263211111093705442175069416"
"589604080719840385096245544436298123098787992724428490918884580156"
"166097919133875499200524063689912560717606058861164671094050775410"
"022569831552000559357297257163626956188267042825248360082325753042"
"0752963450";
int i, j;
long int max;
max = 0;
long int s = 1;
for (i = 0; i < 988; i++) {
int a = 0;
for (j = 1; j <= 13; j++) {
printf("%c", arr[i + a]);
s = s * arr[i + a];
a++;
}
printf("%c%d", '=', s);
printf("\n");
if (s > max) {
max = s;
}
}
printf("\nMaximum product is %d", max);
getchar();
}
Some outputs are zero even if none of the input is zero. The second output happens to be negative. The answers don't even match. Any help is appreciated.
Many set of 13 digits in your char array arr contains zeroes and that is why the multiplication of these sets will result in 0.
There are a couple of issues with your code:
You are using %d instead of %ld to print long int. Using the wrong conversion specifier will result in undefined behaviour.
If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
You are not converting the ASCII value of the digit into its actual value before multiplication. (ASCII value of '0' is 48). This results in integer overflow and is the cause for negative values to be printed.
So the statement:
s = s * arr[i + a];
should be changed to:
s = s * (arr[i + a] - '0');
You are also not resetting the product s to 1 at the beginning of the inner for loop and because of this, you end up multiplying values from the results of different sets of 13.
After making these changes, you can see the live demo here.
There are a few issues to tackle in this code:
Clean up spacing and variable names (an edit by another user helped resolve this issue). Remove redundant variables like a, which j could easily represent by iterating from 0 to 12 rather than 1 to 13. This seems cosmetic but will make it easier for you to understand your program state, so it's actually critical.
Numerical overflow: As with all PE problems, you'll be dealing with extremely large numbers which may overflow the capacity of the long int datatype (231 - 1). Use unsigned long long to store your max and s (which I'd call product) variables. Print the result with %llu.
Convert chars to ints: arr[i+j] - '0'; so that you're multiplying the actual numbers the chars represent rather than their ASCII values (which are 48 higher).
s (really product) is not reset on each iteration of the inner loop, so you're taking the product of the entire 1000-sized input (or trying to, until your ints start to overflow).

How does this array with this indexing work? K&R exercise

I am reading K&R, currently on chapter 1. After reading a section and trying to solve the problems, I like to check out for other solutions online just see different methods to tackle the same problem.
Exercise 1-14 says that we need to print an histogram of the frequencies of different characters in its input. This solution I found only takes into consideration alphabet characters:
#include <stdio.h>
#define MAX 122
#define MIN 97
#define DIFF 32
int main(){
int c = EOF;
int i, j;
int array[MAX - MIN];
printf("%d ", MAX - MIN);
for (i = MIN; i <= MAX; i++){
array[i] = 0;
printf("%d ", i);
}
while ((c = getchar()) != EOF){
if (c >= MIN)
++array[c];
else {
++array[c + DIFF];
}
}
for (i = MIN; i <= MAX; i++){
printf("|%c%c|", i - DIFF, i);
for (j = 1; j <= array[i]; j++){
putchar('*');
}
putchar('\n');
}
return 0;
}
While I understand the logic behind this code, I don't understand how or why the array[] array works. When declaring the array, the size of it is 25 (MAX - MIN). This array should be indexed from 0 to 24. However during the first loop, the array is indexed using values from 97 to 122. But how is it possible to access the array if the indexing starts from a value much larger? Shouldn't the loop be
for (i = 0, i < MAX - MIN; i++)
It makes no sense to me how the array could be indexed from
array[97] ... array[122]
EDIT:
I added printf("%d ", MAX - MIN); and printf("%d ", i); in the first loop myself to try to see if it in fact was indexing the array from 97 onwards.
int array[MAX - MIN];
Here, size of array is 25 because 197-97 = 25.
for (i = MIN; i <= MAX; i++){
array[i] = 0;
Here, index of array[i] is out of bound because size of array is 25 and value and MIN is 97.
Also, ++array[c]; and j <= array[i]; is undefined because out of bound.
GCC compiler generated warning:
source_file.c: In function ‘main’:
source_file.c:14:10: warning: array subscript is above array bounds [-Warray-bounds]
array[i] = 0;
^
source_file.c:20:12: warning: array subscript is above array bounds [-Warray-bounds]
++array[c];
^
source_file.c:20:12: warning: array subscript is above array bounds [-Warray-bounds]
source_file.c:28:27: warning: array subscript is above array bounds [-Warray-bounds]
for (j = 1; j <= array[i]; j++){
^
C11 J.2 Undefined behavior
Addition or subtraction of a pointer into, or just beyond, an array object and an integer type produces a result that points just beyond
the array object and is used as the operand of a unary *operator that
is evaluated (6.5.6).
An array subscript is out of range, even if an object is apparently
accessible with the given subscript (as in the lvalue expression
a[1][7] given the declaration int a[4][5]) (6.5.6).
Indeed the for loop is accessing the array out of bounds, invoking Undefined Behavior, which means that your program may crash or not.
MAX - MIN gives 25 and you access the array with indices in [97, 122], which is definetely wrong.
Similarly, ++array[c] and for (j = 1; j <= array[i]; j++) invoke Undefined Behavior as well, since they go out of bounds too.
PS: You need to declare your array with a size of MAX - MIN + 1, since the english alphabet has 26 letters.
There is no boundary checking in C for arrays, it is the responsibility of the programmer to take care of it.
so when you declare an array as
int array[ MAX - MIN ] ;
you are not restricted to use only sizeof( int ) * (MAX - MIN) but then if you don't use within this range behavior is quite erratic.
there are other programming languages that do enforce array boundary check but not c, unless of course it goes through rigorous compilation steps including string warning checks.
so in this case even though the program works it is not correct.
perhaps the bottom line to understand is
"Working code may not always be a correct code"

While loop with scanf get stack overflow after 8 digits typed

While loop with scanf get stack overflow after 8 number typed. When less amount, everything is ok. What's the problem?
#include <stdio.h>
main ()
{
int x=0;
int j;
int a [x];
while (scanf("%d\n", &a[x++]) == 1);
for (j = 0; j < x; j++)
printf ("%d element of array is \t%d\n\n", j, a[j]);
return 0;
}
How does code in this topic work? I mean the most accepted answer.
This code causes undefined behavior:
int a [x];
Here, a[] is a variable length array, and x has been initialized to 0. In §6.7.6.2 ¶5 about array declarators of the C11 Draft Standard, can be found:
If the size is an expression that is not an integer constant
expression: if it occurs in a declaration at function prototype scope,
it is treated as if it were replaced by *; otherwise, each time it is
evaluated it shall have a value greater than zero.
Since x evaluates to 0 here, in violation of a "shall" outside of the constraints, this is undefined behavior: anything could happen. That anything could happen includes the possibility that the code appears to work for small array indices. But, as it is, this is not a valid C program.
Note that, even in the absence of the first problem, there is another issue. If, for example, x is instead initialized to 1, then a[] is an array of one int. In this case, the line:
while (scanf("%d\n", &a[x++]) == 1);
leads to undefined behavior, since a[x] is already an out of bounds access with x == 1 when input begins.
You are lucky - after 9. Should be instant.
int a[x] - and x is equal zero. so no storage at all.
if size has to be a variable.
int main (void)
{
int x=0;
int y = 10;
int j;
int a [y];
while (x < y )
read_array_item(&a[x++]);
//for (j = 0; j < y; j++) // or x - it does not matter
//printf ("%d element of array is \t%d\n\n", j, a[j]);
return 0;
}

The result of a modulo operation is negative

Why does the following C code produce negative numbers as output? And how do I prevent this from happening?
#include <stdio.h>
int main()
{
int i;
char buf[1024];
for (i = 0; i < 1024; i++)
buf[i] = i%256;
for (i=0; i<1024; i++) {
printf("%d ", buf[i]);
if (i%32==31)
printf("\n");
}
}
Let's look at this line of code:
buf[i] = i%256;
Here, i % 256 is computed as a value of type int. However, buf is an array of chars, so when the value is assigned into the array, it's truncated to a char. If the result of the modulus is outside of the range of positive values that can be stored in a char, it may end up wrapping around and being stored as a negative number instead.
In other words, it's not that the modulus produced a negative value as much as you stored the result in a type that can't hold it. Try changing the array to an int array or unsigned char array and see if that fixes things.
Hope this helps!

If I have to represent integers and char's in a single array, what would be an acceptable way to do this in C?

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

Resources