Behavior of int x[size]={0} - c

I am reading through K&R 2nd Edition and C by Dissection 4th Edition, and came to arrays where they both didn't explicitly state it but I remember from a class that we want to always initialize an array to zero to circumvent garbage being in the indices from previous memory allocations.
I looked online and similar suggestions were made, but I saw an array declaration/initialization I hadn't seen before so I wanted to test it: int x[size]={0}; found here
I wrote a little c program to check things out, and I'm currently going down the rabbit hole it seems.
Can someone please help explain the output?
gcc is compiling to c99, -std=c89 won't compile (because of // type comments so I know it isn't c89 (ansi) ), but looking at the gcc flags I cannot find STDC_VERSION flag to tell me which is; therefore, I've manually compiled like: gcc -Wall -std=c99 -o arrayTest arrayTest.c
The little program is:
#include <stdio.h>
typedef int bool;
#define true 1
#define false 2
#define DEBUG_ true
int main()
{
int x[5] ={0};// what does this do? Guess: Initialize x[0]-x[4] values of 0?
int i=0;// for loop
printf("Hello, World!\n");
if(DEBUG_){
printf("TESTING FOR NULLITY OF INDICES\n");
for(i=0; i<5; i++){
if(x[i]==NULL) printf("The Value at %d is NULL\n", i);
}// If each is null, thats what int x[5]={0} decl/initl does..
// Is 0 NULL in C Language (I wouldn't have thought so..)
}
printf("assigning 0 to all indices of the array..\n");
for(i=0; i<5; i++){ x[i]=0; }
// assigning the array to zeros..
if(DEBUG_){
printf("printing contents of array after filling with zero's\n");
for(i=0; i<5; i++){ printf(x[i]+"\n"); }
// hopefully print out 5 zeros..
printf("SUSPECTING THAT ZERO FILL DIDN'T REPLACE NULL VALUES IN ARRAY\n");
for(i=0; i<5; i++){
if(x[i]==NULL) printf("The Value at %d is NULL\n", i);
}
}
printf("Filling the array, each index has value i*2\n");
for(i=0; i<5; i++){ x[i]= i*2; }
// initialize the array to i*2.
// Expected Values 0, 2, 4, 6, 8
for(i=0; i<5; i++){ printf(x[i]+"\n"); }
// hopefully print out Expected Values
return 0;
}
The output from the program:
-bash-4.3$
-bash-4.3$ arrayTest
Hello, World!
TESTING FOR NULLITY OF INDICES
The Value at 0 is NULL
The Value at 1 is NULL
The Value at 2 is NULL
The Value at 3 is NULL
The Value at 4 is NULL
assigning 0 to all indices of the array..
printing contents of array after filling with zero's
SUSPECTING THAT ZERO FILL DIDN'T REPLACE NULL VALUES IN ARRAY
The Value at 0 is NULL
The Value at 1 is NULL
The Value at 2 is NULL
The Value at 3 is NULL
The Value at 4 is NULL
Filling the array, each index has value i*2
USPECTING THAT ZERO FILL DIDN'T REPLACE NULL VALUES IN ARRAYPECTING THAT ZERO FILL DIDN'T REPLACE NULL VALUES IN ARRAYCTING THAT ZERO FILL DIDN'T REPLACE NULL VALUES IN ARRAY
From the looks of that last line there is a repeating sequence occurring:
USPECTING THAT ZERO FILL DIDN'T REPLACE NULL VALUES IN ARRAY
PECTING THAT ZERO FILL DIDN'T REPLACE NULL VALUES IN ARRAY
CTING THAT ZERO FILL DIDN'T REPLACE NULL VALUES IN ARRAY
I am not sure why this is occurring.
Specifically can someone explain what the array declaration/initialization actually does, why assigning zeros to the array isn't working in this case, why trying to set each index to i*2 doesn't work, and what is going on with the print pattern at the end of the output?

The printf() usage is wrong here. Change
printf(x[i]+"\n");
to
printf("%d\n", x[i]);
See the man page for details.
Also, regarding the initializaion, if you need any reference, see this.

According to the C Standard (6.7.9 Initialization)
21 If there are fewer initializers in a brace-enclosed list than there
are elements or members of an aggregate, or fewer characters in a
string literal used to initialize an array of known size than there
are elements in the array, the remainder of the aggregate shall be
initialized implicitly the same as objects that have static storage
duration.
This means that in this declaration
int x[5] ={0};
the first element of the array is explicitly initialized by 0 and all other elements of the array are implicitly initialized the same way as objects with static storage duration that is they are also initialized by 0.
If you would wriite for example
int x[5] ={1};
then the elements of the array would be initialized like { 1, 0, 0, 0, 0 }
Also take into account that this statement
printf(x[i]+"\n");
does not do what you expect. In this expression x[i]+"\n" there is used the pointer arithmetic becuase string literal "\n" is converted to pointer to its first character and after adding to the pointer value x[i] can result in undefined behaviour. I think you mean
printf( "%d\n", x[i] );
Here is a more interesting example of initializing odd elements of an array with 1 and even elements with 0 which you do not know yet..
#include <stdio.h>
int main(void)
{
int a[] = { [1] = 1, [3] = 1, [5] = 1 };
printf( "The number of elements in the array is %zu\n",
sizeof( a ) / sizeof( *a) );
for ( size_t i = 0; i < sizeof( a ) / sizeof( *a ); i++ )
{
printf( "%d ", a[i] );
}
printf( "\n" );
return 0;
}
The program output is
The number of elements in the array is 6
0 1 0 1 0 1
Thus if for example you want to initialize only the last element of an array with 1 and all other elements with 0 you can write
int a[] = { [4] = 1 };

Related

Do arrays end with NULL in C programming?

I am a beginner to C and I was asked to calculate size of an array without using sizeof operator. So I tried out this code, but it only works for odd number of elements. Do all arrays end with NULL just like string.
#include <stdio.h>
void main()
{
int a[] = {1,2,3,4,5,6,7,8,9};
int size = 0;
for (int i = 0; a[i] != '\0'; i++)
{
size++;
}
printf("size=%d\n", size);
}
No, in general, there is no default sentinel character for arrays.
As a special case, the arrays which ends with a null terminator (ASCII value 0), is called a string. However, that's a special case, and not the standard.
> So I tried out this code, but it only works for odd number of elements.
Try your code with this array -
int a[] = {1,2,0,4,5,6,7,8,9};
^
|
3 replaced with 0
and you will find the output will be size=2, why?
Because of the for loop condition - a[i] != '\0'.
So, what's happening when for loop condition hit - a[i] != '\0'?
This '\0' is integer character constant and its type is int. It is same as 0. When a[i] is 0, the condition becomes false and loop exits.
In your program, none of the element of array a has value 0 and for loop keep on iterating as the condition results in true for every element of array and your program end up accessing array beyond its size and this lead to undefined behaviour.
> Do all arrays end with NULL just like string.
The answer is NO. In C language, neither array nor string end with NULL, rather, strings are actually one-dimensional array of characters terminated by and including the first null character '\0'.
To calculate size of array without using sizeof, what you need is total number of bytes consumed by array and size (in bytes) of type of elements of array. Once you have this information, you can simply divide the total number of bytes by size of an element of array.
#include <stdio.h>
#include <stddef.h>
int main (void) {
int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
ptrdiff_t size = ((char *)(&a + 1) - (char *)&a) / ((char *)(a + 1) - (char *)a);
printf("size = %td\n", size);
return 0;
}
Output:
# ./a.out
size = 9
Additional:
'\0' and NULL are not same.

Explain this method of taking input in array [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
for(int i = 1 ; i <= n ; ++i)
{
scanf("%d" , arr + i);
}
explain this method of taking input in array.
Generally, I try this method for entering elements in array.
for(int i = 1 ; i <= n ; ++i)
{
scanf("%d" , &arr[i]);
}
what is the difference between these two methods?``
I found the former one used in competitive programming...
Here is the "normal" way of using scanf to read n elements into an array:
for(int i = 0; i < n; i++)
scanf("%d", &arr[i]);
Note well that I am calling
scanf("%d", &arr[i]);
with an &, so that I pass a pointer to array[i], so that scanf can fill in that element. (One of the surprising things to remember about scanf is that you must always pass it pointers to fill in, unlike printf, where you pass values to print.)
But if we know how pointers and arrays and pointer arithmetic work, we can then see that this alternative form is equivalent:
scanf("%d", arr + i);
The reason is that when when we mention the array arr in an expression like this, what we get is a pointer to the array's first element. And then arr + i is a pointer to the array's i'th element, which is exactly what we want to pass to scanf, as before.
(Also, you'll notice that I have quietly changed your loop from i = 1; i <= n to i = 0; i < n. Arrays in C are 0-based, so you always want your subscripts to run from 0 to n-1, not from 1 to n.)
The thing is, the second is wrong while the first one is correct - but even then the first one is not robust in that - it doesn't check the return value of scanf().
scanf()'s %d format specifier expects an address of int variable. In the second case you provided the int variable itself (if you enabled compiler warnings this would generate warning message) and the first case you provided the address which results in correct behavior.
In case there are n elements then both of the scanf() would invoke Undefined Behavior because you are accessing an array index out of bound. (Arrays indexing starts from 0 in C).
scanf("%d" , arr + i); is equivalent to scanf("%d",&arr[i]). And the correct way to use scanf() would be
if( scanf("%d", &arr[i]) != 1){
// error occured. Handle it.
}
Also from standard:
d
Matches an optionally signed decimal integer, whose format is the same as expected for the subject sequence of the strtol function with the value 10 for the base argument. The corresponding argument shall be a pointer to signed integer.
To be clear on why both are same:-
The arr+i arr converted to pointer to the first element and then with that pointer we add i - in pointer arithmetic every addition is being directed by the type of element it points to. Here the array is containing int elements - which is why arr+i will point to the i th element of the array. arr+i is a pointer to the ith element which is what is expected by %d format specifier of scanf.
Also &arr[i] - here & address of operator returns the address of the element arr[i] or *(arr+i) which is nothing but the address of the i-th element that is what is being expected by %d format specifier of scanf.
Remember that the argument corresponding to %d in a scanf call must be an expression of type int * (pointer to int). Normally, you'd read an array element as
scanf( "%d", &arr[i] );
The expression &arr[i] evaluates to the address of the element, and it has type int *.
The array subscript operation arr[i] is equivalent to *(arr + i) - given a starting address arr, offset i elements (not bytes!) from that address and dereference the result.
This works because in C, an array expression that isn't the operand of the sizeof or unary & operators is converted ("decays") from type "N-element array of T" to "pointer to T", and the value of the expression is the address of the first element.
Thus, the expression arr by itself will ultimately have type int *, and will evaluate to the address of the first element in the array:
arr == (arr + 0) == &arr[0]
Thus, if
*(arr + i) == arr[i] // int
then it follows that
arr + i == &arr[i] // int *
And this is why
scanf( "%d", arr + i );
works as well as
scanf( "%d", &arr[i] );
As a matter of style, use array subscript notation rather than pointer arithmetic. It conveys the intent more clearly. And, you're less likely to make a mistake with multi-dimensional arrays -
scanf( "%d", &arr[i][j][k] );
is easier to write and understand than
scanf( "%d", *(*(arr + i) + j) + k );
Also, check the result of scanf - it will return the number of items successfully read and assigned, or EOF if end of file has been signaled or there's some kind of input error.
Short version: It's the difference between referring to a value and replacing it with input from the user, and referring to a point in memory and writing to it directly.
In C arrays referring to the name of the variable returns the address of that variable in memory.
The scanf() statement takes input from the user and writes it to a specific point in memory. Applying your second method (the one you are using) you should write something like this:
//YOUR EXAMPLE
#include <stdio.h>
#define n 3
int main()
{
int arr[n];
int i;
printf("Input 3 numbers:\n");
for(i = 0 ; i < n ; i++)
scanf("%d" , &arr[i]);
for(i = 0 ; i < n ; i++)
printf("%d",arr[i]);
}
Here you tell your program to get the value of the array in position i, symbolized by arr[i], and replace that value with the new value obtained from the user.
The other example:
//OTHER METHOD
#include <stdio.h>
#define n 3
int main()
{
int arr[n];
int i;
printf("Input 3 numbers:\n");
for(i = 0 ; i < n ; i++)
scanf("%d" , arr + i);
for(i = 0 ; i < n ; i++)
printf("%d",arr[i]);
}
Here we reference the array by name, meaning we reference to the address of the starting point of where that array is stored in memory. In which case, we do not need the '&' symbol, as we are referring an address directly. The '+ i' term means that every iteration of the loop we refer to the next address in memory in that array (skipping sizeof(int) bytes), and so we write directly to that address.
I don't know for sure which is faster, perhaps these are even equivalent to the compiler, perhaps someone else here would have insights, but both ways would work.
NOTE:
I replaced your for loop boundaries, as you were looping from i=1 to i<=n, and writing to arr[i], which means you weren't utilizing the first element of the array, arr[0], and were out of bounds on arr[n]. (The last cell in the array is arr[n-1].

Code to print the no of elements in an array gives one less than the no of elements

I've written a code to find the number of elements in an integer array as follows:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int arr[] = {2, 3, 5, 5};
int i;
for(i = 0; i < 4; i++)
{
printf("%d %d\n", &arr[i], arr[i]);
}
printf("%d", &arr[i - 1] - arr);
return 0;
}
The last printf prints 3 as opposed to 4 which is the number of elements in the array. Why does the code print one less than the no of elements in the array?
You pass the wrong format specifier to printf. So whatever output you get in the loop is the result of undefined behavior. To print a pointer correctly and portably you must use the %p specifier and pass a void*:
printf("%p %d\n", (void*)&arr[i], arr[i]);
The reason the last printf prints 3 (even though the format specifier is maybe wrong again), is because that's the offset between the the last cell in the array and the beginning. That's what you calculate, so remember that the last cell is indexed with offset 3.
The result of subtracting two pointers can be captured in the type ptrdiff_t. And to print that you'd need the %td format specifier, if we are to make your code more portable again:
printf("%td", &arr[i-1]-arr);
To calculate the array length, you'd need to subtract a pointer to "one passed the end" element of the array (don't worry, calculating that address is not undefined behavior) and a pointer to the beginning. Applying that to the print statement after your loop
printf("%td", (arr + i) - arr);
Which quite expectantly, is just i (4).
Your last printf need correction for specifiers as in your case the difference in first and last position address can easily fit in int but caan produce undefined behaviour so use td specifier as difference in address is of ptrdiff_t type. The problem is that how you calculate your length of array, keep in mind that indexing is done from zero that is if you have array length of 4, last index would be 3 and
array length according to your code is 3 - 0 = 3
but actually it should be 3 - 0 + 1 = 4
change your outside printf to
printf("%td",&arr[i-1] - arr + 1);
I hope this would help you. Also you printf in your for loop needs correct specifier as you are trying to print the address instead of int.

Adding an element to an array in C without a loop

This is my first time asking so please be gentle lol.
So I am trying to better understand arrays in C. Is there a way I can add an element to an array without using a for loop? The problem is I want to add a new element to the end of the array, but without knowing the size of the array.
So I already have this:
#include <stdlib.h> //not sure if needed but put it just in case
int main(void):
float real[20];
real[]={1,2,3,4,5};
I want to add the number 6 to the array, but I don't want to use real[5]=6. Is there another way to add an element to the end of the array without a loop checking if each element in the array until the element is null? Thanks for your help in advance!
C arrays don't know about their length. If you need arrays that can grow and shrink, you have to keep extra information on how long your active array is. An array that is created on the stack like so:
real array[20] = {1, 2, 3};
will contain twenty elements, the first three initialised with concrete values, the rest initialised to zero. If you want to consider this array as an array of initially three values that can hold up to 20 values, you have to keep the actual array length as an extra variable:
real array[20] = {1, 2, 3};
int narray = 3;
You can then append a value. Take care not to overflow that maximum storage of 20 elements:
if (narray < 20) array[narray++] = 9;
You can read the last value and remove it from the array:
if (narray) printf("%g\n", array[--narry]);
Here, you have to take care not to underflow the array. (Also, don't decrement narray more than once in the same expression, which will lead to undefined behaviour.)
If you write a function that operates on the array, pass both array and length:
void array_print(float array[], int n)
{
int i;
for (i = 0; i < n; i++) {
if (i) printf(", ");
printf("%g", array[i]);
}
printf("\n");
}
and call it like so:
array_print(array, narray);
Another approach is to keep a sentinel value like 0.0. This can be useful in some cases, but it has the disadvantage that you have to traverse the whole array to find out the length. It also removes the sentinel from the range of valid values that your array can hold.
The advantage here is, of course, that the array is "self-contained", i.e. you don't have to pass array and length to a function; just the array is enough. When appending you still have to take care not to overflow the maximum storage, which makes this approach cumbersome.
The only way is to keep a pointer to the next free position in the array. For example
#include <stdio.h>
float * copy( const float *src, size_t n, float *dst )
{
while ( n-- ) *dst++ = *src++;
return dst;
}
int main(void)
{
float real[20];
float *p = real;
p = copy( ( float [] ){ 1, 2, 3, 4, 5 }, 5, p );
p = copy( ( float [] ){ 6, 7 }, 2, p );
for ( float *q = real; q != p; ++q ) printf( "%1.1f ", *q );
printf( "\n" );
return 0;
}
The output is
1.0 2.0 3.0 4.0 5.0 6.0 7.0
You always can check whether p points within the array using condition
p < real + 20
The other approach is to use a structure that contains an array. For example
struct Array
{
enum { N = 20 };
float real[N];
size_t n; /* current number of filled elements */
};
With a little help of the preprocessor, you can use a compound literal to get the size:
int main(void)
{
#define REAL_VALUES 1, 2, 3, 4, 5
float real[20] = {REAL_VALUES};
real[sizeof((float[]){REAL_VALUES}) / sizeof(float)] = 6;
return 0;
}
In C you can get the length of an array with the expression sizeof (array) / sizeof (array)[0], or even better, by defining a macro:
#define LEN(array) \
((int) (sizeof (array) / sizeof (array)[0]))
What you describe is not adding an element to the end of the array but rather adding an element after the last element inserted. For that you need a variable that keeps track of the element count:
int count = 0;
float x;
...
if (count < LEN(real)) {
real[count] = x;
count++;
}
Observe, however, that once you have passed the array to a function its length is gone, so you need to pass the array length to the function as well:
void foo(float a[], int len);
...
foo(real, LEN(real));
You can use memset() to make space for your element in your array and then insert your element at specific position.
Here is sample code below.
/*Make space for number to insert.*/
memmove(&arr[pos+1],&arr[pos],(ARR_SIZE+1-pos)*sizeof(int));
arr[pos] = num;/*insert the number.*/
Full code snipet could be found here InsertElement

How could it be possible to read and write past the array

Output of the program:
#include <stdio.h>
int main()
{
int size;
printf("Enter the size of array: ");
scanf("%d",&size);
int b[size],i = 0;
printf("Enter %d integers to be printed: ",size);
while(i++ < size)
{
scanf("%d",&b[i]);
printf("%d %d\n", i, b[i]);
}
return 0;
}
for size = 5 and input numbers :
0 1 2 3 4
is
1 0
2 1
3 2
4 3
5 4
where first column is for i and second for elements of array b.
It is clear that i in the loop while(i++ < size) { incremented to 1 before entering the loop. This loop should have to store/print the value at/of b[1], b[2], b[3], b[4] but not b[5] as loop will terminate at i = 5.
How this code is printing the value of b[5]?
I have tested it for different array size and it is not printing any garbage value.
By reading and writing past the array, your program invokes undefined behavior. It doesn't mean that it has to crash or print garbage values, it can pretend working fine. Apparently, that's what is happening in this case.
In your loop, the condition i < size is checked before i is incremented. But, i is incremented before entering the body of the loop and not after it, so it is possible to access b[5] in this case, as i would be incremented after checking i < size with i=4. You do not want that, as this causes undefined program behavior.
If you try to access an element in the array which does not exist, e.g. array[size], you are accessing the next spot in the memory right after the array. In this case you are lucky, but if this meant you were accessing a part of the memory where your program isn't allowed to do so, you'd get a segmentation fault.
you could use a for cycle instead of a while so instead of while(i++<size)you could use for(i = 0; i < size; i++) that should solve your problem my friend :)

Resources