Passing a 2d-array to a function in C - c

Note I'm using C not C++. I'm working on a program that will take a 2d-array and count the numbers of non-spaces in a subarray. Such as lines[0][i] <-- iterating over line[0][0] - line[0][n]. However, I'm having difficulty getting the function to accept the 2d-array.
Here is my code:
pScore[0]=letters(pLines, 0);
This is the actual function. pScore[] is another array, but a 1d one. pLines is a 4 by 200 2d-array.
int letters(char line[][], int row)
{
int i = 0;
int n = n;
int results = 0;
for( i = 0; i < (sizeof(line)/sizeof(line[0])); i++ )
{
if( !isspace(line[row][i]) )
results++;
}
return results;
}
When I do this it gives me "formal parameter number 1 is not complete". If I remove the second [] from it, the code runs but gives the worng number of non-space characters.

Taking from the comments above, and your function parameter list:
int letters(char line[][], int row)
You violate one primary tenant of passing a 2D array to a function. Specifically, you must always provide the number of columns contained in the array. e.g.
int letters(char line[][5], int row)
char line[][5] is an appropriate parameter. However, whenever you pass an array as a function parameter, the first level of indirection is converted to a pointer. (you will often here this referred to as "pointer-decay", though that is a bit of a misnomer). Therefore a proper declaration that makes this clear is:
int letters(char (*line)[5], int row)
line, after conversion, is a pointer-to-an-array of 5-int. While you can pass the array as line[][5], that is not nearly as informative as (*line)[5]. Let me know if you have any questions.
Numbers Instead of Characters
It is hard to tell what is going on without seeing the remainder of your code. However, I suspect that you are confusing the numerical value and the ASCII character value for the contents of your array. (e.g. character '0' = decimal 48 (0x30 (hex), '1' = 49, 'a' = 97, etc..). See ASCIItable.com

You you pass an array to a function it decays to a pointer. That means char line[][] should really by char (*line)[SIZE_OF_SECOND_ARRAY].
It also means the sizeof trick will not work, as doing sizeof on the pointer line will just return the size of the pointer and not what it points to, you need to explicitly pass the size as an argument to the function.

You need tell function the number of columns of 2d array. Here may help you.

I am not sure if the following statement works with you
for( i = 0; i < (sizeof(line)/sizeof(line[0])); i++ )
where sizeof(line) will be 4 or something like that depends on your platform because "line" is a pointer and you get the size of pointer itself.
Correct me if I am wrong.
In this case, you should pass column number as row's.

Related

Determinant of the matrix — recursive function

I wrote a program which returns a determinant of a matrix. I have a problem, actually; it always returns the "0" value. I notice that my determinant always stays as 0 even though I add numbers to it.
I wrote an English translation in the comments to understand my program better. I use a method in which we select one number and then crossed the element from the column and line of the selected number and then calculate the determinant of the uncrossed elements.
#include<stdio.h>
#include<stdlib.h>
float wznmacierz(float*macierz, int rozmiar)/*"macierz" means a matrix and "rozmiar" is a size of matrix */
{
if (rozmiar == 1)
return *macierz;
float *podmacierz = malloc((rozmiar-1)*(rozmiar-1)*sizeof(float)); // making a second matrix for uncrossed elements.
int wyznacznik = 0; // wyznacznik is the determinant of matrix
for(int element_S = 0; element_S <rozmiar; element_S++) //element s is a number from first line
{
for (int w = 1 ; w < rozmiar; w++ ) //line of checking element
{
for(int kolumna = 0; kolumna < rozmiar; kolumna++)//column of chcecking element
{
if(kolumna == element_S)
continue;
*podmacierz = macierz[(rozmiar*w)+(kolumna)];
podmacierz++;
}
}
wyznacznik += macierz[element_S]*( element_S % 2 ? -1: 1)* wznmacierz(podmacierz, rozmiar-1);
}
return wyznacznik;
}
void main()
{
float a[2][2]={{1,3},{9,8}};
printf("%d", wznmacierz(a,2));
}
Change void main to int main, because main returns an int.
In printf("%d", wznmacierz(a,2)); , change %d to %g, because %d is for formatting an int, but wznmacierz returns a float. %g will format a float. Also add \n after %g to complete the line being output.
In printf("%d", wznmacierz(a,2));, change a to *a because wzmacierz expects a pointer to a float, not a pointer to an array of float. This is a kludge to get your program “working” quickly; see Notes below.
You cannot use podmacierz both to hold the start address of the allocated array and to increment to places within the array. Inside the loop on element_S, put float *p = podmacierz; to make a second pointer, and change the uses of podmacierz inside that loop to p.
Before returning from the function, use free(podmacierz); to release the allocated space.
Notes
In main, a is declared as float a[2][2]. This makes it an array of 2 arrays of 2 float. In the call wznmacierz(a,2), a is automatically converted to a pointer to its first element. That produces a pointer to an array of 2 float. However, wznmacierz is declared with a parameter float*macierz, which is a pointer to a float.
One way to fix this is to pass *a. Once a is converted to a pointer to its first element, a pointer to an array of float, then applying * produces the thing that pointer points to, an array of float. Then that array of float is automatically converted to a pointer to its first element, producing a pointer to a float. You could also write wznmacierz(&a[0][0], 2).
This produces a pointer of the correct type for wznmacierz, which then access the array by calculating element locations, using macierz[(rozmiar*w)+(kolumna)]. This nominally calculates correct addresses for the array elements, since arrays are laid out in memory contiguously, but it is bad style unless necessary, and some people might consider it not to conform to the C standard in a pedantic sense.
One fix would be to define a in main as float a[2*2] = {1, 3, 9, 8};. Then the matrix is implemented as single flat array of float everywhere it is used.
Another fix would be to upgrade wznmarcierz to use two-dimensional arrays. A number of changes are needed to do this. I have not tested them, but I think they are at least:
Change wznmacierz(a,2) to wznmacierz(2, a).
Change the declaration of wznmacierz to float wznmacierz(int rozmiar, float macierz[rozmiar][rozmiar]).
Change the use of macierz inside the function from macierz[(rozmiar*w)+(kolumna)] to macierz[w][kolumna].
Change float *podmacierz = malloc((rozmiar-1)*(rozmiar-1)*sizeof(float)); to float (*podmacierz)[rozmiar-1] = malloc((rozmiar-1) * sizeof *podmacierz);.
Remove the float *p = podmaciarz; that I told you to insert above.
Inside the loop using w, insert float *p = podmacierz[w];.
Change macierz[element_S] to macierz[0][element_S].
Change wznmacierz(podmacierz, rozmiar-1) to wznmacierz(rozmiar-1, podmacierz).

local and global arrays and segmentation fault

I'm having trouble with the following: I want to take a large number (cca. 15-digit) and turn it into individual digits and store them in an array. I will need these digits further on in the code. The problem is, if I declare the array outside the while loop, it stores the first four values, but then I get a segmentation fault. If I declare it within the loop, the code works as I want it to, but then I don't know how to move the array out of that loop, so that I could use it further. How can I solve this? This is what I've compiled:
unsigned long long card_num;
printf("Enter your credit card number:\n");
scanf("%llu", &card_num);
int count = 0;
while (card_num != 0)
{
int digits[count]; //declaring array into which digits will be stored
digits[count] = card_num%10; // get last digit, store it in array
card_num = card_num/10; //remove last digit
printf("Digit[%i] = %i\n", count, digits[count]);
printf("Number of digits: %i\n", count);
count ++;
}
In your code, for the very first iteration
int digits[count];
count is 0, which violates the constraints mentioned in spec. As per C11, chapter 6.7.5.2,
In addition to optional type qualifiers and the keyword static, the [ and ] may delimit an expression or *. If they delimit an expression (which specifies the size of an array), the expression shall have an integer type. If the expression is a constant expression, it shall have a value greater than zero. [....]
and
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
So, this is not a valid code.
As already mentioned, what you are doing is plain wrong.
There is several ways to solve this issue. The easiest would be to allocate an array at the beginning of your program with enough space for all your usecases with something like :
#define MAX_DIGIT 50
int digits[MAX_DIGIT];
Then you just have to check you are not going over this array by checking that count < MAX_DIGIT.
Another way would be using dynamic memory allocation using an int pointer int *digits and malloc (I let you google that) once you know the size of the array you'll need. You'll have to change a bit your code to know the number of digits before starting to get the digits as you need to allocate the memory before starting to store digits.
You could use realloc to keep a code similar to what you already have, but I wouldn't advise it as it is not efficient to realloc memory for each value that you add.
Your logic is fine.
What went wrong is that you tried to increase the length of a fixed-length array while iterating which is not allowed.
You should never change the length of a fixed-length array anywhere in the program.
However if you want to change the length of an array during runtime you must use the malloc and realloc functions to do so.
Check out this example:
//declarations
int *storeNum;
storeNum = (int *)malloc(1 * sizeof(int));
//logic
while(num != 0) {
if(i > 0)
storeNum = realloc(storeNum, (i+1) * sizeof(int));
storeNum[i] = num % 10;
num = num/10;
++i;
}
Here first I declared the array size initially as one and later incremented it using realloc function.
You also have the array size stored in i which you can use later in your code in loops.
But keep in mind that the digits will be stored in your array in reverse order.
Also, you shouldn't declare an array within a loop.
Since you have "declared" the array, each time the compiler enters the loop while iterating it will consider the array-declaration as a new array. That is all.

digit to integer in same order C [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I have a function called fun(int num, int * array); which takes an int and int array as its arugments. I'm trying to convert int to the array.
When i run the program i don't get the array displayed properly
int fun(int num, int*array) {
int count =0;
while(num>0) {
num/= 10;
count++;
}
array[count];
// for loop works
}
When i print the array in the program i.e. everytime I run the program i get random digits.
What this line is supposed to do ?
array[count];
Since your integer array will change in your fun function, you have to allocate the memory (by using malloc, realloc, ...).
edit : plus, you already change the value hold by "num" when you count how many digit there are in "num".
Make a copy of "num" !
edit 2 : the more i look your function, the more it seem you will have problem using it.
Fisrt, you want to explode your integer into an array of int.
Okay, but integer have range, thus meaning integer have a maximum digit.
From my memories, there are 20 digit in an 64bit integer.
So you can simply use "int array[NB_DIGIT_INT_MAX];" with "#define NB_DIGIT_INT_MAX 21".
So, allocating is not necessary AND add complexity in your code (the caller will have to free after the function call).
Second, your fun function doesn't say how many case will hold your integer.
Let's say num = 12, your array will have "array[0] = 1, array[1] = 2", but how do you know where to stop ?
If num = 2345, how do you know that only the 4 first case in your array is legit ?
There are 2 way : You have an another variable that hold the actual size of the array, or you have a special value in your array that say "it's the end" (like '\0' for char array used as string).
You can use "-1".
Let's give a try, and don't hesitate to ask question if thing are unclear (english is not my motherlanguage)
Your array is not even allocated, this can not work as expected. You are even lucky not to have a segmentation fault. If you want to add an integer to an array making it grow, you need to allocate a larger array, copy the values and add the new one to the new array and delete the previous array, keeping array variable as a pointer to the new array. Moreover, you need to pass the size of the actual array as an argument of fun.
The count variable can be global, Initialize it outside all functions like this
short count;
The whole program could be modified like below
#include<stdio.h>
#include<stdlib.h>
short count;
void fun(int num, int **ptr) {
// You need a pointer to a pointer and return type can be void
int num_copy=num;
count=0; // Setting the count to zero
while(num_copy>0) {
num_copy/= 10; // Don't modify the original number
count++;
}
//Allocate enough memory to store the digits
*ptr=malloc(count*sizeof **ptr);
if(NULL==*ptr){
perror("Can't allocate memory");
exit(1);
}
// Then do the loop part with original num
for(int i=count -1; i>=0; i--) {
(*ptr)[i] = num%10;
num /= 10;
}
// By now you have an array 'array' of integers which you could print in main.
}
int main()
{
int number = 123456789;
int *array;
fun(number,&array); // &array is of type pointer to a pointer to integers
//Now print the individual digits
printf("Individual digits are : \n");
for(int i=count-1;i>=0;i--)
printf("%d\n",array[i]);
}
Looks to me like you are converting from an integer to digits. But I don't see where your code writes anything to the array.
If the array wasn't initialized before this, that would explain why it still contains random values.

Pass array as parameter in C

My professor suggested that we should also pass a integer size as the parameter :
int abc(const int data[], int size, int value) {
int i= 0, ans= -1;
while (i < size && ans == -1) {
if (data[i] == value)
ans= i;
i++;
}
return ans;
}
However, I don't think it is necessary to add the integer size in the parameter.
I think the function can be changed to:
int abc(const int data[], int value) {
int i= 0, ans= -1;
while (data[i]!=NULL) {
if (data[i] == value)
ans= i;
i++;
}
return ans;
}
(I know that we are just passing the pointer of the first element of the array in to the function!)
Is the first version has more advantage than the second version?
data[i] being an int value should not be compared against NULL. That's just not correct.
You should pass the size as a separate parameter.
Passing the size as a parameter is a good practice that can protect you from a segmentation fault if the array is malformed.
If you are absolutely certain that the array will contain 0 (which is what NULL is) as a last value, and only as the last value, your solution would also work.
However, if 0 is a valid value in the array, then you will stop as soon as you encounter it.
while (data[i]!=NULL) - there is no guarantee that data[size] would be equal to NULL as you suggested it would be. Without specifying size of the array, the value of data[size] could in fact be anything.
Note that accessing an array out-of-bound results in undefined behaviour. You will just get whatever value left over in that particular memory location, which can be gibberish, and no guarantee of any specific value (including NULL).
Yes, the first version has one major advantage: it actually works!
There are two reasons why yours won't:
Your version loops until NULL is found. NULL is either a pointer to 0 (which will not work), or 0. So what if there are zeroes in the array? You will get early termination.
Your version has not way of knowing when to stop. What if value is not found in the array? You will go on and on and on until there just happens to be 0 in memory. Arrays are not terminated with 0, only character literals are.
data[i]!=NULL for this to work, the element after the last element of the array should be NULL, which I think won't be the case. int cannot be compared with NULL.
However, you can do something similar. You can use a marker to mark the end of the array
Choose some number that you are sure won't appear in the array (may be you know the range of numbers in the array), lets say 99999. Then save it after the last element (do remember you need an array of size one more then the elements you wanna keep). And then use that to check the end of array.
int abc(const int data[], int value) {
int i= 0, ans= -1;
while (data[i]!=99999) {
if (data[i] == value)
ans= i;
i++;
}
return ans;
}
If there is no information about the range
Then you have to send the size of the array along with other parameters to the function.

invalid conversion from 'char' to 'int* in C

I have the following arrays:
int A[] = {0,1,1,1,1, 1,0,1,0,0, 0,1,1,1,1};
int B[] = {1,1,1,1,1, 1,0,1,0,1, 0,1,0,1,0};
int C[] = {0,1,1,1,0, 1,0,0,0,1, 1,0,0,0,1};
//etc... for all letters of the alphabet
And a function that prints the letters on a 5x3 LED matrix:
void printLetter(int letter[])
I have a string of letters:
char word[] = "STACKOVERFLOW";
and I want to pass each character of the string to the printLetter function.
I tried:
int n = sizeof(word);
for (int i = 0; i < n-1; i++) {
printLetter(word[i]);
}
But I get the following error: invalid conversion from 'char' to 'int*'
What should i be doing?
Thanks!!
Behind the parameter type error there is a deeper issue: you lack the mapping between a char and the corresponding int[].
Redefining printLetter as
void printLetter(char letter)
satisfies the compiler, but doesn't solve your problem per se. Whether inside or outside printLetter, you need to get the corresponding int[] for a given char.
A simple brute-force way to achieve this would be to use a switch, but a better way is to use a second array, i.e. something like this:
void printLetter(char letter) {
static int* charToMatrix[] = { A, B, C, ... };
int* matrixToPrint = charToMatrix[letter - 'A'];
// print the matrix
}
Note that this is an example - I don't have access to a C compiler right now, so I can't guarantee it works straight away, but hopefully it illustrates the point well enough. It also lacks bounds checking, so it accesses memory in strange random places, possibly resulting in a crash, if you attempt to print an "unknown" character.
This solution is supposed to work for the uppercase letters; if you need to print lowercase letters or other characters as well, you might prefer going with an array of 256 elements, where only the elements at indexes corresponding to the "known" matrices are filled, and the rest is set to NULL.
You cannot so easly transform the 'a' from "stackoverflow" to the A - the array of ints. You can define all the arrays that represent a letter in one single letter and get them by the convertion of your letter to int.
What you need to do is convert from a character to one of your arrays. So when you have the letter 'A', you'll want to use array A. The easiest way to do this is via lookup table.
int *lookup[256]; // assuming ASCII
memset(lookup, 0, sizeof(lookup));
lookup['A'] = A;
lookup['B'] = B;
...
Then when you have a character, you can get the proper array:
void printletter(char c);
{
int *data = lookup((unsigned char)c);
// In case you get a letter that you don't know how to display
if (data != NULL)
{
// display with data
}
}
Instead of building up your array at runtime, you can also build up your array at compile time although it will be a bit harder as you will need to manually put in NULL pointers.
int *lookup[256] = {
NULL, // you need a total of 65 NULL's
NULL,
...
A, // so this is at the correct position
B,
C,
...
};
The function is declared as void printLetter(int letter[]), which means it takes a pointer to an array of ints. On the other hand, word is an array of chars, and word[i] is a char, which is not at all the right type. If printLetter() is really just supposed to print a single character, you should change its argument to be a char.
void printLetter(int letter[])
should be
void printLetter(char letter)
Because: word is a char[] word[i] is a character.

Resources