I was finding the output of the following C program, which I found on GeeksforGeeks. Here's the program:
#include <stdio.h>
void fun(int ptr[])
{
int i;
unsigned int n = sizeof(ptr)/sizeof(ptr[0]);
for (i=0; i<n; i++)
printf("%d ", ptr[i]);
}
// Driver program
int main()
{
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8};
fun(arr);
return 0;
}
The output of this code was "1 2". But according to me, the output should be just 1. Here is my interpretation of this code:
Firstly, the main function will run, in which after declaring the array "arr", next statement will execute which contains the statement fun(arr).
In that statement, the function "fun" will be called with the argument arr, which contains the address of the first element of the array.
After that, under the function fun, there is a pointer ptr as a parameter. When this function will execute, then the value of n will be calculated as 1 since here the size of ptr is 4 and the size of ptr[0] is also 4.
Next, the loop will run only once since the value of n is 1 and that's why only '1' will get printed since it is the value of ptr[0].
Please help me to find out where I am wrong.
[....] the value of n will be calculated as 1 since here the size of ptr is 4 and the size of ptr[0] is also 4.
Well, that's common, but not guaranteed.
sizeof(ptr) could very well be, result in 8, which is likely in your case, while sizeof(int) can evaluate to 4, resulting a value of 2 for n. This depends on (and varies with) your environment and used implementation.
Try printing them separately, like
printf("Pointer size :%zu\n", sizeof(ptr));
printf("Element size: %zu\n", sizeof(ptr[0]));
and see for yourself.
The size of a pointer on modern platforms is commonly either 4 or 8 bytes.
On a 32-bit platform it's likely that sizeof(ptr) == 4 and n == 1.
On a 64-bit platform it's likely that sizeof(ptr) == 8 and n == 2.
Related
I have this small piece of code:
uint64_t test[] = {1, 2, 3, 4, 5};
printf("test value: %llu\n", test);
I try to print the test array, and it gives me this number:
test value: 140732916721552
Can someone explain this and how an uint64_t array works? Thank you
In your code
uint64_t test[] = {1, 2, 3, 4, 5};
printf("test value: %llu\n", test);
%llu tells printf that it shall print a long long unsigned integer. The test part of the printf statement pass a pointer to the first element of the array to printf. In other words, there is a mismatch between what you are passing (a pointer) and what you tell printf to print (long long unsigned).
In C such a mismatch leads to "undefined behavior". So in general it's not possible to say what will be printed. Any print out will be legal from a C standard point of view. No print out would also be legal. A program crash would be legal. Anything... would be legal.
It's impossible to say what goes on in general. On a specific system, it's possible to dig into the low level things and figure out what is going on. On my system the printed value corresponds to the address of the first array element interpreted as a long long unsigned integer. But don't rely on that. Other systems may do something completely different.
The code below shows how to correctly print the address of the array and the array elements.
#include <stdio.h>
#include <inttypes.h>
int main(void)
{
uint64_t test[] = {1, 2, 3, 4, 5};
// Print the address where the array is located
printf("Address of test value is %p\n", (void*)test);
// Print the values of the array elements
size_t sz = sizeof test / sizeof test[0];
for (size_t i = 0; i < sz; ++i)
printf("test[%zu] is %" PRIu64 "\n", i, test[i]);
return 0;
}
Output (note: address may differ in every invocation):
Address of test value is 0x7ffc4ace5730
test[0] is 1
test[1] is 2
test[2] is 3
test[3] is 4
test[4] is 5
When you define an array like this in C, what you are actually doing is storing each of these values sequentially on the stack as separate uint64_ts. The value assigned to the test identifier is then a pointer to the first of these values, a uint64_t* rather than a uint64_t. When you print test, you are printing the pointer rather than any of the elements, i.e. the memory address of the first element in your array.
The [] notation is equivalent to
*(test + i)
i.e. it dereferences a pointer to the ith element.
I am currently trying to learn about using pointers and functions together in C, which I don't think is easy.
I am trying to print the last element in an array, it actually does the opposite and prints the first element.
I know people normally use for loops, but I can't figure out how to do that with exactly this kind of problem and therefore I thought that I would try it out with an if statement instead.
Edit:
Why is if statement not working in this case? It seems logic that it should work...
My main.c file:
#include <stdio.h>
#include <stdlib.h>
#include "functions.h"
#define Size 7
int main(void)
{
int array1[] = { 11, 88, 5, 9, 447, 8, 68, 4 };
maxValue(array1, Size);
return 0;
}
My functions.h file:
#pragma once
#ifndef FUNCTIONS_H
#define FUNCTIONS_H
int maxValue(const int *, int);
#endif
My functions.c file:
#include "functions.h"
#include <stdio.h>
#include <stdlib.h>
int maxValue(const int *array1, int Size)
{
int max = array1[0];
if (max < array1[Size]) {
Size++;
max = array1[Size];
}
printf("Max value: %d \n", max);
}
Why is if statement not working in this case? It seems logic that it should work...? Because here
if (max < array1[Size]) { }
Size is defined as 7 and you are comparing array1[0] with array1[7] i.e 11 < 4 -> false, hence it doesn't enter into if block, so the last printf executes and that prints max. But its not a correct logic if if blocks becomes true then further Size++ will cause accessing out of bound array elements which cause undefined behavior.
int maxValue(const int *array1, int Size)
{
int max = array1[0];
if (max < array1[Size]) { /* 11 < 4 false, skips if block */
//Size++; /* this is wrong as Size++ here and next accessing array1[Size] cause UB due to accessing out of bound array element */
max = array1[Size];
}
printf("Max value: %d \n", max); /* max is stills array1[0] i.e 11 */
}
Let's simulate what the CPU does when it enters the maxValue function with those arguments. 1. The variable max is assigned the value of array1[0], which is 11.
2. If max (11) is less than array1[7] (4). It is not, so the if block is not executed.
3. Print max: print 11.
Another thing: Your program causes undefined behaviour. Let's take an example where array1[0] is 3, instead of 11. The if block will be executed (3 < 4), so:
Size is incremented to 8.
max is assigned array1[8]. Since the last index in array1 is 7 (that is how you declared the array), you are accessing a memory adress which you are not supposed to access. This is undefined behaviour.
The names maxValue() and max are misleading and confusing what you are trying to do. lastValue() and last would make much more sense.
However what you are trying to do makes no sense in C because arrays are of known length, so you can access the last element directly:
int array1[] = { 11, 88, 5, 9, 447, 8, 68, 4 };
int array_length = sizeof(array1) / sizeof(*array1) ;
printf("Lastvalue: %d \n", array1[array_length - 1] ) ;
However you cannot do this in a function because arrays are not first class data types in C and when passed to a function will "degrade" to a simple pointer without any information regarding the size of the array pointed to. The calling function having the size information must pass that too (as you have done, but then appeared to get very confused):
void printLast( int* array, int length )
{
printf( "Lastvalue: %d \n", array1[length - 1] ) ;
}
It is difficult to see why you thought you might need any other code or what your maxValue() function is intended to achieve. The "logic" which you say "should work" is thus:
If value of the first array element is less than the value of the last array element, then print the undefined value one past the end of the array; otherwise print the first element of the array.
If you wanted to print the last element, then you simply print it, the value of the first element has nothing to do do with it. Either way you should not index past the end of the array - that value is undefined.
I wrote two functions and call the functions in main.
Function 1 – I wrote a function that returns void and takes an int * (pointer to integer array) or int[], and int (for the size). The function needs to initialize all the elements of the array to non-zero values.
Function 2 – I wrote another function that returns int and takes an const int * (pointer to integer array) or int[], and int (for the size). The function should sum all the elements of the array and return the sum.
In main I defined an integer array of size 5. Called function 1 in main to initialize the values of the array. Called function 2 in main to get the sum and print the value of the sum to the console.
My problem is the program runs but the print out for sum we are getting is a large (in the millions), random, number and is not the expected answer of 15. Anyone who can help us get the correct answer would be greatly appreciated
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#pragma warning(disable: 4996)
void func1(int* ptr, int size);
int func2(const int* ptr, int size);
int main()
{
int grid[5];
func1(grid, 5);
func2(grid, 5);
}
void func1(int* ptr, int size)
{
*ptr = 1, 2, 3, 4, 5;
}
int func2(const int* ptr, int size)
{
int sum;
sum = ptr[0] + ptr[1] + ptr[2] + ptr[3] + ptr[4]; // *(ptr + 0); putting an asterisk makes it so that it changes the entire "ptr" value and the "[0]" value
printf("\n\nThe sum of the integers in the array is %d.\n\n", &sum);
}
*ptr = 1, 2, 3, 4, 5;
does not do what you think it does. It actually evaluates all the integer constants but sets ptr[0] to be 1 (see comma operator for more detail), leaving all the others at some arbitrary value.
Note that it is not evaluating *ptr = (1, 2, 3, 4, 5) (which would set *ptr to 5) but is actually evaluating (*ptr = 1), 2, 3, 4, 5 - this works because something like 42 is actually a valid C statement, albeit not very useful.
If you're trying to set the array to increasing values, just use something like:
for (int i = 0; i < size; i++)
ptr[i] = i + 1;
You probably also want to do that when summing the values since it should depend on the passed-in size rather than just summing five values:
int sum = 0;
for (int i = 0; i < size; i++)
sum += ptr[i];
Additionally, the value you are printing out is not the sum, it's the address of the variable containing the sum (a decent compiler will warn you about this). You should be using sum in your printf rather than &sum.
And, as a final note, the signature for func2 indicates that you should actually be returning the sum rather than just printing it. So I would suggest removing the printf from that function and simply doing:
return sum;
Then you can put the printf into the caller (main) as follows:
int main(void)
{
int grid[5];
func1(grid, sizeof(grid) / sizeof(*grid));
int sum = func2(grid, sizeof(grid) / sizeof(*grid));
printf("The sum of the integers in the array is %d.\n\n", sum);
return 0;
}
Note the use of sizeof(grid) / sizeof(*grid), which is basically the number of array elements in grid - this will allow you to resize grid by simply changing it in one place to something like int grid[42] and still have all the code work with the updated size.
Not actually necessary for your code but it's best to get into good programming habits early (more descriptive names for your functions may also be a good idea).
Line *ptr = 1, 2, 3, 4, 5; assigns ptr[0] value and leaves other spots unitilized so when you sum it, it will be random memory.
You should use for like this to initialize
for(int i=0;i<size;i++)
{
ptr[i] = i+1;
}
and similiar aproach to sum it.
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.
char str[] = "beautiful earth";
memset(str, '*', 6);
printf("%s", str);
Output:
******ful earth
Like the above use of memset, can we initialize only a few integer array index values to 1 as given below?
int arr[15];
memset(arr, 1, 6);
No, you cannot use memset() like this. The manpage says (emphasis mine):
The memset() function fills the first n bytes of the memory area pointed to by s with the constant byte c.
Since an int is usually 4 bytes, this won't cut it.
If you (incorrectly!!) try to do this:
int arr[15];
memset(arr, 1, 6*sizeof(int)); //wrong!
then the first 6 ints in the array will actually be set to 0x01010101 = 16843009.
The only time it's ever really acceptable to write over a "blob" of data with non-byte datatype(s), is memset(thing, 0, sizeof(thing)); to "zero-out" the whole struture/array. This works because NULL, 0x00000000, 0.0, are all completely zeros.
The solution is to use a for loop and set it yourself:
int arr[15];
int i;
for (i=0; i<6; ++i) // Set the first 6 elements in the array
arr[i] = 1; // to the value 1.
Short answer, NO.
Long answer, memset sets bytes and works for characters because they are single bytes, but integers are not.
On Linux, OSX and other UNIX like operating systems where wchar_t is 32 bits and you can use wmemset() instead of memset().
#include<wchar.h>
...
int arr[15];
wmemset( arr, 1, 6 );
Note that wchar_t on MS-Windows is 16 bits so this trick may not work.
The third argument of memset is byte size. So you should set total byte size of arr[15]
memset(arr, 1, sizeof(arr));
However probably, you should want to set value 1 to whole elements in arr. Then you've better to set in the loop.
for (i = 0; i < sizeof(arr)/sizeof(arr[0]); i++) {
arr[i] = 1;
}
Because memset() set 1 in each bytes. So it's not your expected.
Since nobody mentioned it...
Although you cannot initialize the integers with value 1 using memset, you can initialize them with value -1 and simply change your logic to work with negative values instead.
For example, to initialize the first 6 numbers of your array with -1, you would do
memset(arr,-1,6*(sizeof int));
Furthermore, if you only need to do this initialization once, you can actually declare the array to start with values 1 from compile time.
int arr[15] = {1,1,1,1,1,1};
Actually it is possible with memset_pattern4 which sets 4 bytes at a time.
memset_pattern4(your_array, your_number, sizeof(your_array));
No, you can't [portably] use memset for that purpose, unless the desired target value is 0. memset treats the target memory region as an array of bytes, not an array of ints.
A fairly popular hack for filling a memory region with a repetitive pattern is actually based on memcpy. It critically relies on the expectation that memcpy copies data in forward direction
int arr[15];
arr[0] = 1;
memcpy(&arr[1], &arr[0], sizeof arr - sizeof *arr);
This is, of course, a pretty ugly hack, since the behavior of standard memcpy is undefined when the source and destination memory regions overlap. You can write your own version of memcpy though, making sure it copies data in forward direction, and use in the above fashion. But it is not really worth it. Just use a simple cycle to set the elements of your array to the desired value.
Memset sets values for data types having 1 byte but integers have 4 bytes or more , so it won't work and you'll get garbage values.
It's mostly used when you are working with char and string types.
Ideally you can not use memset to set your arrary to all 1.Because memset works on byte and set every byte to 1.
memset(hash, 1, cnt);
So once read, the value it will show 16843009 = 0x01010101 = 1000000010000000100000001
Not 0x00000001
But if your requiremnt is only for bool or binary value then we can set using C99 standard for C library
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h> //Use C99 standard for C language which supports bool variables
int main()
{
int i, cnt = 5;
bool *hash = NULL;
hash = malloc(cnt);
memset(hash, 1, cnt);
printf("Hello, World!\n");
for(i=0; i<cnt; i++)
printf("%d ", hash[i]);
return 0;
}
Output:
Hello, World!
1 1 1 1 1
The following program shows that we can initialize the array using memset() with -1 and 0 only
#include<stdio.h>
#include<string.h>
void printArray(int arr[], int len)
{
int i=0;
for(i=0; i<len; i++)
{
printf("%d ", arr[i]);
}
puts("");
}
int main()
{
int arrLen = 15;
int totalNoOfElementsToBeInitialized = 6;
int arr[arrLen];
printArray(arr, arrLen);
memset(arr, -1, totalNoOfElementsToBeInitialized*sizeof(arr[0]));
printArray(arr, arrLen);
memset(arr, 0, totalNoOfElementsToBeInitialized*sizeof(arr[0]));
printArray(arr, arrLen);
memset(arr, 1, totalNoOfElementsToBeInitialized*sizeof(arr[0]));
printArray(arr, arrLen);
memset(arr, 2, totalNoOfElementsToBeInitialized*sizeof(arr[0]));
printArray(arr, arrLen);
memset(arr, -2, totalNoOfElementsToBeInitialized*sizeof(arr[0]));
printArray(arr, arrLen);
return 0;
}