Get count of an array from within a function - c

I'm trying to write a function that prints the elements of a given array. However, I don't understand how I can count the elements of the array which is passed into my function. Here's the code:
In this example, I am trying to get the count from within my function, though this only returns 1.
#include <stdio.h>
void first_function(int ages[], char *names[]) {
int i = 0;
int count = sizeof(*ages) / sizeof(int);
for(i = 0; i < count; i++) {
printf("%s has lived %d years.\n", names[i], ages[i]);
}
}
int main(int argc, char *argv[])
{
int ages[] = { 7, 32, 36 };
char *names[] = {
"Tiger", "Sandy",
"Ryan"
};
first_function(ages, names);
printf("---\n");
return 0;
}
In this example, I give the function an extra parameter (count), then get the count from within main. Is this the normal way to do it? It seems unclean somehow.
#include <stdio.h>
void first_function(int ages[], char *names[], int count) {
int i = 0;
for(i = 0; i < count; i++) {
printf("%s has lived %d years.\n", names[i], ages[i]);
}
}
int main(int argc, char *argv[])
{
int ages[] = { 7, 32, 36 };
char *names[] = {
"Tiger", "Sandy",
"Ryan"
};
int count = sizeof(ages) / sizeof(int);
first_function(ages, names, count);
printf("---\n");
return 0;
}

Your so-called unclean way is the normal way. (The sizeof idiom does not work if the array parameter has decayed to a pointer type). Although consider using a size_t type for the count, not an int.
Another approach is to use a particular value to signal the end of the array. Effectively this is how the string library functions work in C; with NUL signalling the end of the string.

According to the C Standard (6.7.6.3 Function declarators (including prototypes))
7 A declaration of a parameter as ‘‘array of type’’ shall be adjusted
to ‘‘qualified pointer to type’’, where the type qualifiers (if any)
are those specified within the [ and ] of the array type
derivation....
So this function declaration
void first_function(int ages[], char *names[]);
is equivalent to the following declaration after adjusting the corresponding parameters declared like arrays.
void first_function( int *ages, char **names );
That is the parameters ages and names have pointer types within the function.
As result this expression
int count = sizeof(*ages) / sizeof(int);
(I think you mean
int count = sizeof(ages) / sizeof(int);
^^^^
nevertheless)
is equivalent to
int count = sizeof( int) / sizeof(int);
because the type of the sub-expression *ages is int.
If you will write the expression like
int count = sizeof(ages) / sizeof(int);
then it is equivalent to
int count = sizeof(int *) / sizeof(int);
and again will not yield the size of the array passed as the argument.
For such arrays that do not have a sentinel value you have to pass also their sizes to functions if it is required.
Thus the function should be declared like
void first_function(int ages[], char *names[], size_t n);
and called like
size_t count = sizeof(ages) / sizeof(*ages);
first_function(ages, names, count);
Pay attention to that there is no need to initialize the variable i within the function two times. The function can look like
void first_function(int ages[], char *names[], size_t count)
{
for ( size_t i = 0; i < count; i++)
{
printf("%s has lived %d years.\n", names[i], ages[i]);
}
}

Yes you can't use sizeof here to get the length of the array in the called function. Because array decays into pointer here in the called function. And that's why it will return sizeof pointer not size of array.
Solution- you need to pass another parameter specifying the size of the array or keeping a place holder like NULL or some value to mark the end of the array. (Well you have followed that in your second solution - which is perfectly fine and it works).
Return value of sizeof is size_t. Use size_t instead of int.
It's the right way to handle what sizeof operator returns.

Related

Regarding question about function pointer in C?

I was reading about function pointer. That it contains address of instructions. And there I encountered one question to find an element in array using function pointer. Here is the code.
#include <stdio.h>
#include <stdbool.h>
bool compare(const void* a, const void* b)
{
return (*(int*)a == *(int*)b);
}
int search(void* arr, int arr_size, int ele_size, void* x, bool compare(const void*, const void*))
{
char* ptr = (char*)arr; // Here why not int *ptr = (int*)arr;
int i;
for (i = 0; i < arr_size; i++)
{
if (compare(ptr + i * ele_size, x))
{
return i;
}
}
return -1;
}
int main()
{
int arr[] = { 2, 5, 7, 90, 70 };
int n = sizeof(arr) / sizeof(arr[0]);
int x = 7;
printf("Returned index is %d ", search(arr, n, sizeof(int), &x, compare));
return 0;
}
In the search function char *ptr = (char*)arr; is used which is giving perfect answer = 2.
But when I have used int *ptr = (int*)arr; it gives -1 as answer.
Why is this? Can anyone explain this?
A char is the smallest addressable unit in any C program, and on most system it corresponds to a single byte. That treats the array as a generic sequence of bytes, and uses the ele_size to calculate the byte-position of each element with ptr + i*ele_size.
If you use int *ptr then the byte-position calculation will be wrong by a factor of sizeof(int) (typically 4), since the pointer arithmetic will be done in units of the base type (int instead of char).
The function search knows nothing about what is the type of elements of the array pointed to by the pointer arr of the type void *.
So casting the pointer to the type int * does not make a sense. If to do so then the expression ptr + i*ele_size where the pointer arithmetic is used will produce an incorrect result.
That it contains address of instructions
There is a subtle difference between normal (object) pointers and function pointers. It is not possible to access the single instructions of a function - they do not have the same length.
With other pointers the increment (arithmetic) is adapted to the type, whether as p[i] or p + i or *(p+i).
Side note: there still is int at the bottom of the call chain:
return (*(int*)a == *(int*)b);

C - Copying array in other array as output argument

I am trying understand how pointers works in C. I am trying a simple case where an array, and a pointer to array are the arguments of a function which will copy the elements of the first one in the second one.
I have written this code
#include <stdio.h>
#define TAM 32
typedef int TablaArray[32];
void copyArray(TablaArray, TablaArray*, int);
void main(){
int t1[] = {1,2,3,4};
int t2[4];
copyArray(t1, t2,4);
for(int i = 0; i <= 3; i ++){
printf("%d - %d\n", t1[i], t2[i]);
}
}
void copyArray(TablaArray t1, TablaArray *t2, int tam){
for(int i = 0; i<tam-1; i++){
printf("%d\n", t1[i]);
*t2[i] = t1[i];
}
}
I am expecting to get something like this with the printf expression:
1 - 1
2 - 2
3 - 3
4 - 4
But definitely I don't know the way... I have been looking in stackoverflow and because I am sure this trivial question is already answered... but I didn't find it...
You need to make sure you are passing two int pointers pointing to both arrays. In your code only one of the arguments is a pointer. The code below should make it more clear:
#include <stdio.h>
void copyArray(int * arr1, int * arr2, int size);
int main(void)
{
int t1[] = {1,2,3,4};
int t2[4];
copyArray(t1, t2,4);
for(int i = 0; i <= 3; i ++)
{
printf("%d - %d\n", t1[i], t2[i]);
}
return 0;
}
void copyArray(int * arr1, int * arr2, int size)
{
for(int i = 0; i < size; i++)
{
printf("%d\n", arr1[i]);
arr2[i] = arr1[i];
}
return;
}
Edit: in what you have written, a TablaArray * is a pointer to an array of 32 ints, while you need an int *
typedef int TablaArray[32];
is bad practice
The problem is connected with array to pointer decay and then with pointer arithmetics:
Pointer decay means that if you pass an array-object of type int x[32] as argument to a function, then it "decays" to a pointer like int *, which points to the first element of the integer array. So be aware that if you pass an int x[32]-object, it's actually passed by reference (the array is not copied) and you may alter the contents of the array in the function.
Now pointer arithmetics:
Incrementing a pointer (or accessing an array through array subscripting) implicitly does pointer arithmetics, and the number of bytes added to the initial value depends on the type of the object to which the pointer points:
typedef int Array10[10];
Array10 arr = { 1,2,3,4,5,6,7,8,9,0 };
int *x = arr; // arrayOfInts decays to a pointer; x points to the &arr[0]
x++; // in terms of bytes, x is incremented by sizeof(int) bytes
int i = x[3]; // gets the int-value on the address of x + 3*sizeof(int)
Array10 *arr10ptr = arr;
arr10ptr++; // in terms of bytes, x is incremented by sizeof(Array10) bytes, which is 10*sizeof(int)
arr10ptr[3]; // 3*sizeof(Array10), i.e. 3*10*sizeof(int)
Now it should be clear why a function parameter being declared as a pointer to an array of int[32] behaves different from a function parameter being declared as an int[32].
So you could correct your program as follows, now knowing that TablaArray t2 will be a reference to the underlying array anyway:
void copyArray(TablaArray t1, TablaArray t2, int tam){
for(int i = 0; i<tam; i++){
printf("%d\n", t1[i]);
t2[i] = t1[i];
}
}
Hope it helps.
Compile with warnings enabled. If you used gcc -Wall -Werror, you would get the following errors:
luis.c:10:6: error: return type of ‘main’ is not ‘int’ [-Werror=main]
void main(){
^~~~
luis.c: In function ‘main’:
luis.c:15:19: error: passing argument 2 of ‘copyArray’ from incompatible pointer type [-Werror=incompatible-pointer-types]
copyArray(t1, t2,4);
^~
luis.c:8:6: note: expected ‘int (*)[32]’ but argument is of type ‘int *’
void copyArray(TablaArray, TablaArray*, int);
^~~~~~~~~
cc1: all warnings being treated as errors
The first one is simple, it should be int main.
The second one is a bit harder to see exactly because you used a typedef. So your prototype is now
void copyArray(int *, int (*)[32], int);
With the second value being a pointer-to-array that by itself is a construct that is not used often.
Instead, you'd just need two pointers to int here, and the size of an array should perhaps use size_t instead:
void copyArray(int *, int *, size_t);
void copyArray(int *t1, int *t2, size_t n){
for (int i = 0; i < tam; i++) {
t2[i] = t1[i];
}
}
Finally, if you use a C99, C11 compiler, it could be nice to use the variable-length arrays arrays to tell that one of the parameters tell the sizes of the arrays; for that we need to reorder the parameters:
void copyArray(size_t, int[*], int[*]);
void copyArray(size_t n, int t1[n], int t2[n]) {
...
}
void copyArray(TablaArray, TablaArray, int); // prototype
void copyArray(TablaArray t1, TablaArray t2, int tam){
for(int i = 0; i<tam; i++){
printf("%d\n", t1[i]);
t2[i] = t1[i];
}
}
this will help
// much faster
#include <string.h>
void copyArray(TablaArray t1, TablaArray t2, int tam){
memcpy(t2, t1, sizeof(t1[0]) * tam);
}
In Your Copy function you were copying the same value of T1 to T2 on the Address Of T2. you can do it with out pointers but pointers helps you to refer the Address

Sum of an array

I can't understand why my program only prints the first number in the array.
it seems it loops only once and then something breaks the loop. The output is 232.
#include <stdio.h>
int main( int argc, char* argv[]){
int sum_arr(int arr[]);
int arr[5]={232,44,3,4,5};
printf("%d\n",sum_arr(arr));
return 0;
}
sum_arr(int arr[]){
int i,sum=0,sizeofarr=sizeof(arr)/sizeof(arr[0]);
for(i=0;i<=(sizeofarr-1);i++){
sum+=arr[i];
}
return (sum);
}
sizeofarr = sizeof(arr) / sizeof(arr[0]);
This trick to calculate the size of an array doesn't work. Because in the function, arr decays to a pointer, not an array.
To fix the problem, pass the size explicitly.
Change the code the following way
#include <stdio.h>
nt main( int argc, char* argv[])
{
int sum_arr( int arr[], size_t n );
int arr[5] = { 232, 44, 3, 4, 5 };
printf( "%d\n", sum_arr( arr, sizeof( arr ) / sizeof( *arr ) ) );
return 0;
}
int sum_arr( int arr[], size_t n )
{
int i = 0, sum = 0;
for ( ; i < n ;i++ )
{
sum += arr[i];
}
return ( sum );
}
The problem with your code is that an arrray passed as an argument is implicitly converted to a pointer to its first element. So inside function sum_array you used sizeof( int * ) / sizeof( int ) that for your system is equal to 1.
Take into account this quote from the C Standard (6.3.2.1 Lvalues, arrays, and function designators)
3 Except when it is the operand of the sizeof operator or the unary &
operator, or is a string literal used to initialize an array, an
expression that has type ‘‘array of type’’ is converted to an
expression with type ‘‘pointer to type’’ that points to the initial
element of the array object and is not an lvalue. If the array object
has register storage class, the behavior is undefined.
Remember, in C when pass an array as an argument to a function, actually you're passing a pointer to an array.
Since the size of a pointer and an int is 4 or 8, you'll be getting sizeof(int *)/sizeof int (4/4=1 for 32-bit machines and 8/4=2 for 64-bit ones) which is 1 or 2.
In conclusion, array names in a C program are (in most cases) converted to pointers.One exception is when we use the sizeof operator on an array. If arr was converted to a pointer in this contest, sizeof(arr) would give the size of a pointer and not of the actual array, which would be rather useless, so in that case a means the array itself.
In my program the array passed in the function is converted to a pointer. Then, sizeof(arr) in the sum_arr function gives the size of a pointer and not of the actual array.
This program should be execute in this way:
#include <stdio.h>
#define SIZEOFARR(arr) (sizeof(arr)/sizeof(arr[0]))
int main(){
int sum_arr(int arr[],int size);
int arr[5]={232,44,3,4,5};
printf("The sum of the array is: %d\n",sum_arr(arr,SIZEOFARR(arr)));
return 0;
}
int sum_arr(int arr[],int size){
int i,sum=0;
for(i=0;i<size;i++){
sum+=arr[i];
}
return (sum);
}

Parsing pointer parameter in C

This code take 5 strings and sort them in ascending way.
void swap (char data[5][255], int i, int j) {
char temp[255];
strcpy(temp,data[i]);
strcpy(data[i],data[j]);
strcpy(data[j],temp);
}
void sort (char data[5][255], int n) {
// * : first address contact
int i, j;
for(i = 0; i < n-1; i++)
for( j = i+1; j > 0; j--)
if(strcmp(data[j-1],data[j])>0)
{
printf("%s",data[j-1]);
swap(data, j-1, j);
}
}
int main() {
char strings[5][255];
char comp[255];
int i, n;
n = sizeof(strings)/sizeof(comp);
printf("Enter 5 strings, max 255 chars each:\n");
for(i=0; i < n; i++)
scanf("%s",strings[i]);
sort(strings, n);
printf("Sorted data:\n");
for(i=0; i < n-1; i++)
printf("%s, ",strings[i]);
printf("%s.\n",strings[i]);
return 0;
}
In addition of that, how can I possibly parse my static array string[5][255] to function by using pointer?
I tried that, for example,
void sort ( char **data, int i ) { ... }
but it throws out error like this.
incompatible pointer types passing 'char [5][255]' to parameter of type 'char **'
Is there anything I can parse my array using pointer?
Since array parsed to function its first address(pointer), I thought function will accept those expression. Please give me some advice to understand.
The parameter you must pass is not a pointer to a pointer char**, but a pointer to a char array char(*)[255]
void sort (char (*data)[255], int n)
When you pass an array, you can omit the size of the first dimension
void sort (char data[][255], int n)
which is equivalent to char(*)[255].
char** is a pointer, which points to another pointer. Whereas char(*)[255] is a pointer, which points to an array.
You have to understand the difference between: char **data vs char (*data)[255]
Those are two different types because the allocation of memory may be different:
When char **data is used pointer arithmetic may not work properly, meaning data could be scattered all over the memory
When char (*data)[255] is used pointer arithmetic works perfectly because all elements of array are adjacent to each other
As I wrote you in the comment char[][] doesn't decay to char** but it decays to char(*)[] ( char (*data)[255] in your case) as the first element decay in a pointer which is not a "pointer to a pointer" but a pointer to an array of 255 characters. It is possible to use a char** pointer if you do something like this (c++):
char **array = new char *[N];
for(int i = 0; i<N; i++)
array[i] = new char[N];
or using the malloc (c).
As #newact suggests it is important to distinguish between
char *data[255] -> char *[255]data = => "data is an array of 255 pointers to char"
And
char (*data)[255] -> char [255](*data) => "data is a pointer to an array of 255 chars"
Try to make the following changes:
void swap ( char *data, int i, int j)
*(data + index1*255 + index2)

Pointer issue in C

Greetings,
I am trying to learn pointers in C, I simply want my "addtwo" function to add 2 to every element of the input integer array, yet I get odd compilation errors, here is the non-pointer version which indeed won't properly compile.
addtwo(int *arr[]) {
int i=0;
for(;i< sizeof(arr)/sizeof(int);i++) {
arr[i] = arr[i] + 2;
}
}
main() {
int myarray[] = {1,2,3,4};
addtwo(myarray);
}
Regards
You've some problems. First, you try to pass a int* to a parameter that's type int**. That won't work. Give it type int*:
void addtwo(int *arr){
int i=0;
for(;i< sizeof(arr)/sizeof(int);i++){
arr[i] = arr[i] + 2;
}
}
Then, you need to pass the size in an additional argument. The problem is, that when you pass arrays, you really pass just a pointer (the compiler will make up a temporary pointer that points to the array's first element). So you need to keep track of the size yourself:
void addtwo(int *arr, int size){
int i=0;
for(;i<size;i++){
arr[i] = arr[i] + 2;
}
}
int main(void) {
int myarray[] = {1,2,3,4};
addtwo(myarray, sizeof myarray / sizeof myarray[0]);
}
Now it will work. Also put the return type before them. Some compilers may reject your code, since it doesn't comply to the most recent C Standard anymore, and has long been deprecated (omitting the return type was the way you coded with the old K&R C).
addtwo(int *arr[]) should be addtwo(int *arr)
You cannot use sizeof to get the size of an array from a pointer. Typically you would either pass the size of the array as a separate arg or have some special value marking the last element.
Not to do with the compile error, but...
You have to pass sizeof(arr) to the function instead of calling it in the function. When an array is passed to a function, C no longer sees it as an array, but as a single pointer to memory, so that sizeof(arr) as you are calling it now, will return the size of the pointer arr, which is most likely 4.
Here's what I mean in code:
void addtwo(int *arr, int size){
int i=0;
for(;i< size;i++){
arr[i] = arr[i] + 2;
}
}
int main(){
int myarray[] = {1,2,3,4};
addtwo(myarray, sizeof(arr)/sizeof(int));
return 0;
}
In C a notation int *arr[] is the same as int** arr.
You need to pass a pointer to the first element of the array and the array size. Array types decay to pointers in the context of function parameters. Try:
void addtwo(int *arr, size_t size){
for(size_t i = 0; i < size; i++){
arr[i] = arr[i] + 2;
}
}
int main() {
int v[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
addtwo(v, sizeof v / sizeof v[ 0 ]);
return 0;
}
Though others already gave the correct response, basically you have an array of pointers when you have
int *arr[]
I doubt that is what you want. If you have
int arr[]
then that will also be equivalent to
int *arr
addtwo argument declaration really reads:
arr is an array of pointers to integer
when you probably really want
a pointer to an array of integers
"How to Read C Declarations" has really helped me to grok the topic a while ago, maybe it will do the same for you.

Resources