I want to know why this program, that i create just for practice, don't works properly. The program asks for 5 numbers that put in an array called "array". There are also 2 VOID functions, one for get the numbers, that uses a for cicle and scanf instruction , and another, that has to print the 5 numbers in the array. The problem is that the numbers printed are only the firsts 4. What's wrong?
P.S. Sorry for my ignorance but i'm a beginner. Here's the code
#include <stdio.h>
#include <stdlib.h>
void
array_print(int array[],size_t size){
int i;
for(i=0;i<size;i++){
printf("%i ",array[i]);
}
}
void
get_num(int array[],size_t size){
int i;
for(i=0;i<size;i++){
scanf("%i",&array[i]);
}
}
int
main(){
int array[5];
size_t size;
size=sizeof(int);
printf("Insert 5 numbers: ");
get_num(array,size);
array_print(array,size);
return 0;
}
In the environment where you run the program sizeof(int) is equal to 4.
The size of the array can be calculated like
size = sizeof( array ) / sizeof( int );
Take into account the type of the value returned by the operator sizeof is size_t. So it would be better to use this type for the size of the array.
Also you could introduce a manifest constant for number 5. As for example
#define N 5
and declare the array like
int array[N];
Or if the compiler supports variable length arrays you could write
int main( void )
^^^^^^^^^^^^^^^^
{
const size_t N = 5;
int array[N];
//...
The architecture of the compiler in which you're executing your code is 32bit so the size of int is 32bits = 4 bytes.
size = sizeof(int)
will return
size = 4
and you will be only able to enter four values.
Related
I will go straight to what I'm asking for, I also see some similar question but is not what I'm looking for...so it seems I have to ask with a new forum.
I'm preparing myself for a future examination, where is not required the pointer, but I would like to get some extra information and abilities.
Here's the code followed by the question...
I'm using Fedora 33, I know is different from some IDE on Windows (ex: Visual Studio or Dev C++)
/* It's just a simple test, if this work I will get myself into a more complicated one, as you could read in the
* forum, I'm getting ready ( just a recheck of my abilities ) for an universitary examinaton. */
#include <stdio.h>
#include <stdlib.h>
#define N 5
void casual_generation(int** mat);
void prompt_print(int** mat);
int main()
{
int **mat[N][N];
casual_generation(**mat);
prompt_print(**mat);
}
void casual_generation(int** mat)
{
int i=0,j=0;
for(i=0;i<N;i++)
for(j=0;j<N;j++)
mat[i][j] = rand() % 50;
}
void prompt_print(int** mat)
{
int i=0,j=0;
for(i=0;i<N;i++)
{
for(j=0;j<N;j++)
printf("%d ", mat[i][j]);
printf("\n");
}
}
Somebody else on the forum used malloc, struct or other stuff, as you can see in this picture, when I try to execute him it says "Segmentation fault (core dumped)"
screen error
Where is my error?
And if you want, can you also send me the version with the passed value pointer?
Thanks for whoever will give me an answer, and time dedicated.
This declaration
int **mat[N][N];
does not make a sense. It means that you have a matrix elements of which are pointers of the type int **. But you need a matrix elements of which are integer numbers of the type int. That is you need a declaration like this
int mat[N][N];
So now you have a two-dimensional array (or matrix) of integers.
As you are going to pass this two-dimensional array to functions then used as an argument expression it is converted to pointer to its first element of the type int ( * )[N].
Correspondingly the functions that accepts such an array should be declared like
void casual_generation( int mat[][N], size_t n );
void prompt_print( int mat[][N], size_t n );
or (that is fully equivalent) like
void casual_generation( int ( * mat )[N], size_t n );
void prompt_print( int ( *mat )[N], size_t n );
because the compiler adjusts function parameters having array types to pointers to array element types.
Now for example the first function can be defined the following way
void casual_generation( int ( * mat )[N], size_t n )
{
for ( size_t i = 0; i < n; i++ )
{
for ( size_t j = 0; j < N; j++ )
{
mat[i][j] = rand() % 50;
}
}
}
And the function can be called like
casual_generation( mat, N );
A similar way can be defined the function prompt_print.
Using the second parameter makes the function more general. For example it can be called for two-dimensional arrays with different numbers of rows.
Now I will explain why you are getting a segmentation fault in your original code.
You have this declaration
int **mat[N][N];
a two dimensional array of pointers of the type int **.
Then you are using the expression **mat as an argument of function calls like this
casual_generation(**mat);
Then you are applying the dereference operator like *mat the array designator is converted to pointer to its first element (row) having the type int ** ( * )[N]. So dereferencing this pointer you get the first row of your array int **[N]. Applying the second time the dereferenced operator to this expression that has an array type the used expression is again is converted to pointer to its first element of the type int **( * ). That is it points to the first element of the first row of the original two-dimensional array. Dereferencing this pointer you get the first element of the type int **. This uninitialized pointer with indeterminate value the function accepts as its argument.
Thus dereferencing this first uninitialized element of the original matrix within the function
mat[i][j] = rand() % 50;
^^^
you get a segmentation fault. The reason of the fault is the incorrect matrix and the corresponding function parameter as it was shown above in tbe beginning of the answer.
Where is my error?
The "Segmentation fault" error happens because you define the variable mat as a pointer, but don't allocate any memory for it to point to.
int **mat[N][N];
You meant to do
Int mat[N][N];
and
casual_generation(mat);
prompt_print(mat);
By passing **mat you are passing mat[0][0] that is an int, but you want to pass the whole matrix which is a pointer to pointers to int (i.e. int **)
And you may want to introduce srand() in your code.
Just to make things clear:
mat is of type int ** and it's the whole matrix (or if you want it's a pointer to the first row)
*mat is of type int * and it's the first row of the matrix (or if you want it's a pointer to the first element of the first row)
**mat is of type int and it's the first element of the first row of the matrix
int **mat[N][N];
Here, you defined a double pointer to a 2D array. You only need to use one of those - a double pointer or a 2D array, like so:
int mat[N][N];
However, the bigger problem comes from trying to interchange 2D arrays and double pointers. This isn't possible in C since the 2D array is laid out flat in memory.
You need to create an array mat_ptr of pointers yourself and then pass that to casual_generation and prompt_print.
Finally, these casual_generation and prompt_print functions expect to be given a pointer, so you shouldn't dereference the pointer with ** before calling the function.
The final working code is:
int main()
{
int mat[N][N];
int *mat_ptr[N];
for (int i = 0; i < N; i++)
mat_ptr[i] = mat[i];
casual_generation(mat_ptr);
prompt_print(mat_ptr);
}
As you can find a detailed explanation why the code crashed in the other answer I will only propose a quite elegant solution that uses a neat though little known feature from C99 called Variable Length Arrays (aka VLA).
#include <stdio.h>
#include <stdlib.h>
void casual_generation(int n, int mat[n][n]);
void prompt_print(int n, int mat[n][n]);
int main()
{
const int N = 5;
int mat[N][N];
casual_generation(N, mat);
prompt_print(N, mat);
}
void casual_generation(int n, int mat[n][n])
{
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
mat[i][j] = rand() % 50;
}
void prompt_print(int n, int mat[n][n])
{
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
printf("%d ", mat[i][j]);
printf("\n");
}
}
It compiles in pedantic mode with no warnings and it works like a charm.
VLA were introduced to C to simplify numerical computation over multidimensional arrays.
#include <stdio.h>
void print(int (*p)[3]);
int main(void)
{
int a[3] = {1, 2, 3};
print(&a);
return 0;
}
void print(int (*p)[3])
{
for (int i = 0; i < sizeof(*p) / sizeof(**p); i++)
printf("%d\n", (*p)[i]);
}
I have written a C function. See above.
It can print all the elements in an array.
There is one thing which is not so perfect : The number of array elements seems to be known in advance.
So I made some modification in hopes of making the function universal :
#include <stdio.h>
void print(int (*p)[]);
int main(void)
{
int a[3] = {1, 2, 3};
print(&a);
return 0;
}
void print(int (*p)[])
{
for (int i = 0; i < sizeof(*p) / sizeof(**p); i++)
printf("%d\n", (*p)[i]);
}
In the function, p is pointer pointing to the entire array.
However, it fails to be compiled.
Why can't int (*p)[] be used as an argument for C function?
int (*p)[] can be used as an argument for the function. The part of your code that gives the error is sizeof *p which is obviously not possible, because the type of *p is int[] which is an incomplete type and hence has no known size.
For the function to know the length of the array, you must design a way for the function to receive this information. Options include:
what you did in the original code.
passing the length as another argument.
including the length as an array element.
having a sentinel value on the end of the array.
The most common idiom would be to pass int *p, size_t n, you do not really gain anything by using pointer-to-array without the dimension being given.
The problem is that int [] is an incomplete type as the array has no defined size and therefore its sizeof cannot be taken.
In "modern C" (i.e. for almost 2 decades) you could have used variable-length arrays for this - you can pass the size as an argument and then the array:
#include <stdio.h>
#include <stdlib.h>
void print(size_t n, int (*p)[*]);
int main(void) {
int a[3] = {1, 2, 3};
print(3, &a);
}
void print(size_t n, int (*p)[n]) {
for (size_t i = 0; i < sizeof(*p) / sizeof(**p); i++)
printf("%d\n", (*p)[i]);
}
Of course this gains you nothing, since sizeof *p / sizeof **pp will be ... n. Therefore we might as well have used
void print(size_t n, int p[n]) {
for (size_t i = 0; i < p; i++)
printf("%d\n", p[i]);
}
which is less typing.
Short answer: int (*p)[] can't be used as an argument and have the function magically know the array size, because the standard says so.
Longer answer:
int (*p)[] is a pointer to an array, but the array has no defined size. So by looking at the array, it is impossible to do pointer arithmetic, calculate size of the thing p is pointing at, etc..
You don't have array of arrays so you don't need int (*p)[]. You have an array of int, so int *p or int p[] should be enough. This does not solve the problem of knowing the size of your array in print. To do this you basically have 3 options
Hardcode the value in the function
Put a sentinel value in your array to mark the end
Pass the size as a separate parameter like this:
void print(int n, int p[n])
Just remember that whatever method you use, parameter passing of arrays will always use pointers behind the scenes, so you CAN NOT use sizeof(p) to calculate the size of the array. sizeof will always return the size of a pointer in those situations
C novice here.
I am trying to write a program containing function that takes in an array pointer, and each element of the array passed in the main function is incremented by 1. This is what I have tried:
#include <stdio.h>
#include <stdint.h>
void array_incr(int8_t *, uint8_t);
int main (void){
int8_t *arr[] = {0xAB, 0xCB, 0xC4, 0x84};
array_incr(arr, sizeof(arr)/sizeof(arr[0]);
int i;
for (i = 0; i < 4; i++)
printf("%d", arr[i]);
}
void array_incr(int8_t *arr, uint8_t len){
int i;
for(i=0; i<len; i++)
arr[i]++;
}
This is compiling with a lot of warnings and errors. Could someone please tell me where I am going wrong, while maintaining the same format of implementation?
Multiple problems indeed:
Incorrect type in declaration int8_t *arr[] = {0xAB, 0xCB, 0xC4, 0x84};: you should remove the * as arr is an array of numbers, not an array of pointers. Furthermore, the values are larger than 127 which is the maximum value for type int8_t, you should use uint8_t or a larger type.
Missing ) at the end of array_incr(arr, sizeof(arr)/sizeof(arr[0]);
There is no \n in the printf("%d", arr[i]); output statement. The values will come out in a single sequence of digits (and negative signs, since the values are actually negative for type int8_t).
Here is a corrected version:
#include <stdio.h>
#include <stdint.h>
void array_incr(uint8_t *, uint8_t);
int main(void) {
uint8_t arr[] = { 0xAB, 0xCB, 0xC4, 0x84 };
array_incr(arr, sizeof(arr) / sizeof(arr[0]));
int i;
for (i = 0; i < 4; i++)
printf("%d\n", arr[i]);
}
void array_incr(uint8_t *arr, uint8_t len) {
int i;
for (i = 0; i < len; i++)
arr[i]++;
}
First of all, it would be best to include said list of warnings and errors, but with such a small program it's mostly alright.
Into the matter, you declared your array wrong ; it should be int8_t arr[] (you included an extra *). You want an array of integers, not a pointer to an array of integers nor an array of pointers to integers (you can't initialise the former like that anyway).
sizeof doesn't work like you think it does. It returns the number of bytes taken up by the variable or type in memory. For example, on most modern system sizeof(int) returns 4, as would something like int a = 1; sizeof(a), and just like sizeof(arr) in your case. arr is not an array, it's a pointer to an array, so it's technically an int (thus 4 bytes). You would have to create an additional variable and manually hold the array's size if it were to change.
EDIT : tried it, seems to work. I remember that it doesn't but apparently it does ...
#include <stdio.h>
#include <stdlib.h>
int constChars(const char* str) {
int size = sizeof(str)/sizeof(char);
printf("Size is %d.\n", size);
int i = 0;
for (i=0;i<size;i++)
printf("%c ", str[i]);
return 0;
}
int main(void) {
char a[10]={'b','c','d','e','f','f','f','f','f','f'};
constChars(a);
return 0;
}
I wrote piece of code like above, but the output result is:
Size is 8.
b c d e f f f f
I'm quite confused, why the sizeof() function gives a size of 8?
I use gcc and freebsd.
When you pass an array to a function, it gets rewritten as a pointer, where sizeof information is lost. If you did this in main instead, i.e:
char a[10]={'b','c','d','e','f','f','f','f','f','f'};
int size = sizeof(a)/sizeof(a[0]);
printf("Size is %d.\n", size);
It prints 10 as expected. But once you pass it to constChars, it prints the size of a pointer.
Str is a pointer to a char. That is typically 4 to 8 bytes. You are not getting the size of the array, but the size of the variable. The only way to know the length of the array is to pass the size in with it, or you could deliminate the array with some sort of signal value (like \0) and do some iteration.
I want to make a random sized array everytime program executes at first but compiler yells me
"Error 2 error C2466: cannot allocate an array of constant size 0"
Is there any way that I can randomly choose the SIZE by SIZE = rand() % 100 at the beginning and then intialize the array with int myarray[SIZE]={0} ??? or should I everytime initialize it with an exact number at the beginning?
int main(void) {
int i;
int SIZE=rand()%100;
int array2[SIZE]={0};
for(i=0;i<SIZE;i++) //fill the array with random numbers
array2[i]=rand()%100;
...
}
You indicated you're using Microsoft's visual studio. MS visual studio is not c99 compilant (they cherry pick at best) and one of the missing features is VLAs.
The best you'll be able to do with MS VS is to do this dynamically using malloc():
int main(int argc, char *argv[])
{
int i;
int SIZE=rand()%100;
int *array2=malloc(SIZE * sizeof(int)); // allocate space for SIZE ints
for(i=0;i<SIZE;i++) //fill the array with random numbers
array2[i]=rand()%100;
free(array2); // free that memory when you're done.
return 0;
}
If you want to switch compilers, there are other options.
You can use malloc() or calloc() to do this in C. For example,
int SIZE=(rand()%100)+1; // size can be in the range [1 to 100]
int *array2 = (int*) malloc(sizeof(int)*SIZE);
But at the same time, the array size can not be anything other than a constant value.
The following two declarations are valid.
int a[10];
and
#define MAX 10
int b[MAX];
But you will get an error if you try to declare using the following methods.
int x=10;
int a[x];
and
const int y=10;
int b[y];
Note that rand()%100 can and will be 0. If you want a random value 1 <= n <= 100 then you need to use (rand()%100)+1
The best way to do this would be to make your array a pointer and use malloc:
int SIZE=(rand()%100) + 1; //range 1 - 100
int *array2 = malloc(sizeof(int) * SIZE);
Afterwards you can use array2 much as you would use an array.