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

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"

Related

Enter unknown number of array values in C/C++ has strange behaviour

I need to populate an array of integers with an unknown number of elements. I am using a while loop to input values and exit the loop as a non integer value is entered. Outside the loop an integer j is initialized at 0 and used to address array elements inside the loop. At each round of the loop I check the value of j before and after the input value is assigned to array element v[j], then j is incremented.
Depending on the size chosen for the array in the declaration, (in the example below v[8]), index j is unexpectedly affected by the assignment itself: in the example below when j equals 11 before the assignment it becomes 2 after the assignment, thereafter messing it all up. As a result the code fails to assign the correct input values to the array.
I am surely lacking some deeper knowledge about C/C++ array management... anyone can help to to fill the gap explaining the apparently strange behaviour of my code?
#include <stdio.h>
int main()
{
int j = 0, m, v[8];
printf("Enter an integer: to finish enter x\n");
while (scanf("%d", &m))
{
printf("j before assignment:%d - ", j);
v[j] = m;
printf("j after assignment:%d - ", j);
printf("v[j] after assignment:%d\n", v[j]);
j++;
}
return 0;
}
You write beyond the array boundaries of v. To avoid this, check j in a for loop, e.g. replace while (...) with
for (j = 0; j < 8 && scanf("%d", &m) == 1; ++j) {
// ...
}
This way, the loop stops after the end of the array (v[7]) is reached.
To comment the "strange" behaviour, read about stack and stack layout, e.g. Does stack grow upward or downward?
As always, check the C tag wiki and the books list The Definitive C Book Guide and List

Trying to make a function which squares all values in an array. Getting strange number on the last value

int squaring_function (int *array, int i);
int main()
{
int array[5];
int i;
for(i=0; (i <= 5) ; i++)
{
array[i] = i;
printf("\nArray value %d is %d",i,array[i]);
}
for(i=0; (i <= 5) ; i++)
{
array[i] = (squaring_function(array, i));
printf("\nSquared array value %d is %d",i,array[i]);
}
return 0;
}
int squaring_function (int *array, int i)
{
return pow((array[i]),2);
}
I'm trying to use this squaring_function to square each value in turn in my array (containing integers 0 to 5). It seems to work however the last value (which should be 5)^2 is not coming up as 25. cmd window
I have tried reducing the array size to 5 (so the last value is 4) however this prints an incorrect number also.
I'm quite new to C and don't understand why this last value is failing.
I'm aware I could do this without a separate function however I'd quite like to learn why this isn't working.
Any help would be much appreciated.
Thanks,
Dan.
There are 2 bugs in your code. First is that you're accessing array out of bounds. The memory rule is that with n elements the indices must be smaller than n, hence < 5, not <= 5. And if you want to count up to 5, then you must declare
int array[6];
The other problem is that your code calculates pow(5, 2) as 24.99999999 which gets truncated to 24. The number 24 went to the memory location immediately after array overwriting i; which then lead to array[i] evaluating to array[24] which happened to be all zeroes.
Use array[i] * array[i] instead of pow to ensure that the calculation is done with integers.
The code
int array[5];
for(int i=0; (i <= 5) ; i++)
exceeds array bounds and introduces undefined behaviour. Note that 0..5 are actually 6 values, not 5. If you though see some "meaningful" output, well - good or bad luck - it's just the result of undefined behaviour, which can be everything (including sometimes meaningful values).
Your array isn't big enough to hold all the values.
An array of size 5 has indexes from 0 - 4. So array[5] is off the end of the array. Reading or writing past the end of an array invokes undefined behavior.
Increase the size of the array to 6 to fit the values you want.
int array[6];
The other answers show the flaws in the posted code.
If your goal is to square each element of an array, you can either write a function which square a value
void square(int *x)
{
*x *= *x;
}
and apply it to every element of an array or write a function which takes an entire array as an input and perform that transformation:
void square_array(int size, int arr[size])
{
for (int i = 0; i < size; ++i)
{
arr[i] *= arr[i];
}
}
// ... where given an array like
int nums[5] = {1, 2, 3, 4, 5};
// you can call it like this
square_array(5, nums); // -> {1, 4, 9, 16, 25}

Can an array in C be indexed by a character?

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.

How do I assign a value, to a 2D array location in C?

So I'm quite a newbie, so please go soft.
I have created a 2D array, 60x30 and want to display it on the screen as a grid, by doing a double for loop. I am using a simple character '.' for each slot of the grid just for a test.
char FrameBuffer[29][59];
for (int i = 0; i <= 29; i++)
{
for (int j = 0; j <= 59; j++)
{
FrameBuffer[i, j] = '.';
printf("%c ", FrameBuffer[i,j]);
}
printf("\n");
}
However, whenever I try and assign a value to a position in my 2D array, e.g.
FrameBuffer[0,1] = '.',
I am greeted with an error:
Expression must be a modifiable lvalue
FrameBuffer[29][59] This is a 29x59 array, you need a 30x60.
Please don't mix up array declarations with array indexing. Array declarations are fully sane; if you need 30x60 then you type FrameBuffer[30][60]. When you access the array however, you start at index 0.
Simply change the code to:
char FrameBuffer[30][60];
for (int i = 0; i < 30; i++)
{
for (int j = 0; j < 60; j++)
{
FrameBuffer[i][j] = '.'; // note the correct syntax here
EDIT
As a curious side-effect, FrameBuffer[i, j] is interpreted as something entirely different than intended. The comma here is regarded as the comma operator, a special kind of operator which evaluates the left expression i, then the right expression j, then returns j.
Meaning that the code ended up completely equivalent to FrameBuffer[j] = '.'. Where FrameBuffer[j] is a whole array, not a char. You can't assign a value to an array this way, an array is not a "lvalue", which explains the compiler error text.
FrameBuffer[i,j] = '.';
printf("%c ", FrameBuffer[i,j]);
modify these two statements to
FrameBuffer[i][j] = '.';
printf("%c ", FrameBuffer[i][j]);
[i,j] means nothing to the compiler. It's nothing but an invalid syntax.
also correct you array.
FrameBuffer[29][59]it is an array of row=29 and col=59
change it to FrameBuffer[60][30];

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;
}

Resources