Subscripted value not array nor pointer - c

I have a program that reads a 2d array from a file, and makes it a jagged array (where each row is sized perfectly to fit all non-zero elements). Then it prints the array out.
But I have a couple issues I can't figure out.
Specifically
26: I get a warning (assignment makes integer from pointer without cast
44: error: subscripted value is neither array not pointer
What can I do to fix it?
int main() {
FILE *inputFile1 = fopen("denseMatrix1.txt", "r");
char inputBuffer[SIZE];
int dim1, dim2, input, i, j;
int *mtrx1;
fgets(inputBuffer, SIZE, inputFile1);
sscanf(inputBuffer, "%d%d", &dim1, &dim2);
mtrx1 = malloc(sizeof(int *) * dim1);
for (i=0; i<dim1; i++) {
int cols=0;
int *row = malloc(sizeof(int) * cols);
fgets(inputBuffer, SIZE, inputFile1);
for (j=0; j<dim2; j++) {
sscanf(inputBuffer, "%d", input);
printf("i=%d j=%d input=%d\n", i, j, input); // ADDED LINE (NOT PRINTING)
if (input) {
cols++;
row = realloc(row, sizeof(int) * cols);
row[cols-1] = input;
}
}
mtrx1[i] = row;
cols=0;
}
int mtrx3[DIM1][DIM2] = {0};
// Prints first 2 matrices
printf("First matrix: \n");
printMatrix(mtrx1, dim1);/*
return 0;
// Prints a 2d array matrix
void printMatrix(int *mtrx, int dim1) {
int i, j;
for (i=0; i<dim1; i++) {
for (j=0; j<(sizeof(mtrx[i]) / sizeof(int)); j++) {
printf("%d ", mtrx[i][j]);
}
printf("\n");
}
printf("\n\n");
Contents of file denseMatrix1.txt:
7 8
0 0 0 5 1 0 0 5
0 0 0 0 0 0 0 0
0 0 0 0 1 2 0 0
1 0 0 0 0 0 0 0
3 0 0 5 0 0 3 0
1 0 0 0 0 3 0 0
0 0 0 0 0 0 0 1

In stead of
int *mtrx1;
use
int **mtrx1;
With the former declaration, mtrx[i] evaluates to int. You need it to evaluate to int* to be able to use:
mtrx1[i] = row;
Update
Your strategy of using fgets to get a line of text and using the line of text with sscanf is not going to work in a for loop.
Let's take the first line of the matrix:
0 0 0 5 1 0 0 5
and the for loop:
for (j=0; j<dim2; j++) {
sscanf(inputBuffer, "%d", input);
printf("i=%d j=%d input=%d\n", i, j, input); // ADDED LINE (NOT PRINTING)
if (input) {
cols++;
row = realloc(row, sizeof(int) * cols);
row[cols-1] = input;
}
}
In the for loop, you will end up 0 being assigned to input every time for the first line. sscanf does not store what you read the first time and continue from what's left.
You'll need to come up with a different strategy. For example:
for (i=0; i<dim1; i++) {
int cols=0;
int *row = malloc(sizeof(int) * cols);
fgets(inputBuffer, SIZE, inputFile1);
char* token = strtok(inputBuffer, " \n");
for (j=0; j<dim2; j++) {
input = atoi(token);
printf("i=%d j=%d input=%d\n", i, j, input);
if (input) {
cols++;
row = realloc(row, sizeof(int) * cols);
row[cols-1] = input;
}
token = strtok(NULL, " \n");
}
mtrx1[i] = row;
cols=0;
}

Line 26 Warning
Here is the line in question:
mtrx1[i] = row;
And here are the declarations for these variables:
int *mtrx1;
int ..., i, ...;
int *row = ...;
As your warning message says, you are trying to take a pointer value, row, and assign it to an array of ints. Assuming that what you want is mtrx1 to be an array of individual row sub-arrays, you should change its type accordingly – from int *, which is an array of ints, to int **, which would be an array of arrays of ints.
Line 44 Error
Relevant code:
void printMatrix(int *mtrx, int dim1) {
int i, j;
...
printf("%d ", mtrx[i][j]); // line 44
...
}
The error on this line is the result of a problem similar to the one above – mtrx is declared as a one-dimensional array of int, but in line 44 you have two subscripts as if it is a two-dimension array. This is also fixed by changing the type of mtrx to int **.
For Loop
The for loop is failing to iterate over all values because your sscanf line is ambiguous – there's no space between your %d values, and so sscanf can't tell which number should be which, and it reads them through as one value. This means dim2 is never properly set.
For this sort of bug, using breakpoints is the usually the easiest way to get an idea of what's going on in the program, particularly for loops. If you haven't looked into them yet, you should.
Additional Info
Line 26 gives you a warning while line 44 gives you an error because of the way pointers are defined in relation to ints in C. C allows for "pointer arithmetic," which means pointers can be treated as plain numbers in addition to referring to objects or arrays.
When you subscript an array in C, the type of the expression effectively just drops a *; for example, subscripting a int * array has a type of int. So when you try to assign a pointer to int *mtrx1, it treats it like trying to assign a pointer to an int variable, and so the pointer gets converted to its raw numeric value. This is perfectly legal C, but is considered by most programmers to be fairly bad practice (for various reasons), and so the compiler gives you a warning for it.
Line 44 is sort of the opposite case – your mtrx[i][j] expression is equivalent to (mtrx[i])[j]. Since mtrx is defined as just a int *, this means you effectively end up trying to subscript an int, which is flat out illegal in C. No warning, just an error.

Related

How do i use a pointer in C to return a value?

I am trying to make a pointer P return to me the index of the first occurrence of given number in an array using count function that i wrote (J's job is to return the number of occurrences), the idea here is that im trying to write a function that returns 2 values instead of 1 (P returns index of first occurrence and J returns its number) in such way:
int count(int h[],int *p,int size,int d)
{
int j=0;
int bool = 0;
for(int i=0; i<size ;i++)
{
if(h[i]==d && bool == 0)
{
j++;
bool = 1;
p = &i;
}
else if(h[i]==d)
j++;
}
if(bool==0)
{
j=-1;
*p=-1;
return j;
}
else
return j;
}
void main ()
{
int j;
int *p = NULL;
int h[] = {1,2,3,4,5,1,1,3,4};
j = count(h, p , sizeof(h)/sizeof(int) , 1);
printf("%d %d", *p,j);
}
I am fully aware aware that instead of using int *p, i can simply use P and pass its address in such way:
void printarray(int h[],int size){
for(int i=0;i < size ;i++)
{
printf(" %d ",h[i]);
}
printf("\n");
}
int count(int h[],int *p,int size,int d)
{
int j=0;
int bool = 0;
for(int i=0; i<size ;i++)
{
if(h[i]==d && bool == 0)
{
j++;
bool = 1;
*p = i;
}
else if(h[i]==d)
j++;
}
if(bool==0)
{
j=-1;
*p=-1;
return j;
}
else
return j;
}
void main ()
{
int j;
int p;
int h[] = {1,2,3,4,5,1,1,3,4};
printarray(h,sizeof(h)/sizeof(int));
j = count(h, &p , sizeof(h)/sizeof(int) , 1);
printf("%d %d", p,j);
}
What Really intrigues me is that why does it show a segmentation fault when using the pointer ? or am i just wrong about using a pointer in the first place and i should pass the address of an int in case i want my function to return 2 values for me ?
That which is a pointer has to point to something. So when you wrote int *p = NULL; you didn't give it somewhere to point. You could have done int n; int *p = &n; and proceed to pass p.
But it gets bumpy from here. You tried to write p = &i; inside the function. While that's completely valid code, from that point, assigning to *p will mess up your loop control function. This is not what you want. In the "I know I can" section you have the more reasonable *p = i;.
I'm guessing you want to know how to pass something allocated in the function to its caller. You can in fact do this; there's standard library functions designed for this task. You can in fact write
int count(int h[],int **p,int size,int d)
{
int j=0;
int bool = 0;
for(int i=0; i<size ;i++)
{
if(h[i]==d && bool == 0)
{
j++;
bool = 1;
*p = malloc(sizeof(int));
**p = i;
}
else if(h[i]==d)
j++;
}
if(bool==0)
{
j=-1;
return j;
}
else
return j;
}
void main ()
{
int j;
int *p = NULL;
int h[] = {1,2,3,4,5,1,1,3,4};
j = count(h, &p , sizeof(h)/sizeof(int) , 1);
if (p) {
printf("%d %d", *p,j);
free(p);
} else {
printf("(no index) %d", j);
}
}
So what happened here is we have a pointer in main() that is initialized to point nowhere, may or may not be set in count to point to the index. If nothing is found, p will still point to NULL (nowhere). The function malloc() returns the newly allocated memory so that p has somewhere to point; and the function free returns it.
** is a simple idea that gives people headaches. Since a pointer is * we add another * when we want a pointer to a pointer, so we can change that pointer. Just don't ask how deep you can go. The answer is don't try. Two happens a lot; three requires a good justification, and more than three is almost never done. More than two really is a headache and nobody wants headaches on their headaches. The limit is way higher. Nobody goes there.
It probably seems rather pointless, and it is. malloc() is used to allocate entire arrays in the function (whose size isn't known until runtime) and return them to the caller. A single int just isn't worth managing like this (the pointer is bigger than it is), but for an array it makes sense. So much that in big programs, almost everything is on the heap; unlike the small programs everybody starts with where almost everything is on the stack (local variables are on the stack).
You thinking about what you want to do correctly, but you are over complicating how to do it a bit. Instead of all the if ... else ... statements, what if you just used a flag like what you call bool (but let's rename it to something that won't conflict with the type from stdbool.h), call it first_set instead. Initialize it with a value of 0 (false) to begin with, and then when you find the first occurrence, update first_set = 1;
If you step back and thing of what your primary check needs to be, all you are really worried about locating in your array is the first, and all remaining indexes where the given value (let's call val instead of d) is equal to the array element. (and since a count, a length and an array index cannot be negative, let's choose size_t as the type for the positive counting values). To track the number of occurrences, let's use occurs as the variable (helps keep things readable in long programs)
So all you really want to do is loop over each element in your array and check if the current element is equal to the value you are searching for. That is the primary concern from which all other actions can be taken. You can keep your parameters in the order you like, but I find it easier to think about the function (1) taking an array, (2) of a given number of elements, where I will find (3) the first occurrence or (4) a given value. (whatever makes sense to you, but is also readable to whoever works on your code later) So with a slight tweak of the ordering (at least for my old eyes), you could set up your function to loop over each element and locate all of the occurrences of a given value as:
size_t arr_occurrences (int *a, size_t nelem, size_t *first, int val)
{
int first_set = 0; /* flag if 1st occurrence set */
size_t occurs = 0; /* total no. of occurrences */
for (size_t i = 0; i < nelem; i++) { /* loop over each element */
if (a[i] == val) { /* is it equal to val? */
...
occurs += 1; /* increment no. of occurrences */
}
}
return occurs; /* return total number of occurrences */
}
The only thing left to add is how to set the first occurrence. While you talk in terms of locating the "address" of the first occurrences in the function, what I think you really mean is locating the "index" of the first occurrence within the array. You can convert the index back to an address in the calling function and not have to worry about passing something that can hold the address (which would require passing a pointer-to-pointer rather than a pointer-to int)
So the first time the test of a[i] == val tests true, you want to capture the index and save it, ensuring you don't change it for any of the other times a[i] == val tests true during your loop. You have your first_set flag that is currently set to 0 (false), so all you really need to capture your first index in the array where val occurs is:
if (!first_set) { /* if first not set */
*first = i; /* update value at address of first */
first_set = 1; /* set first_set flag true */
}
If you put that in place of the ... placeholder in the function above, you would have:
size_t arr_occurrences (int *a, size_t nelem, size_t *first, int val)
{
int first_set = 0; /* flag if 1st occurrence set */
size_t occurs = 0; /* total no. of occurrences */
for (size_t i = 0; i < nelem; i++) { /* loop over each element */
if (a[i] == val) { /* is it equal to val? */
if (!first_set) { /* if first not set */
*first = i; /* update value at address of first */
first_set = 1; /* set first_set flag true */
}
occurs += 1; /* increment no. of occurrences */
}
}
return occurs; /* return total number of occurrences */
}
Short and sweet, no else needed, just a check of your flag first_set and if it isn't set, capture the index and set first_set true so you don't change in during the remainder of your loop. Your function makes the index of the first occurrence of val available back in the calling function by updating the value at the address held by the pointer first. The function returns the total number of occurrences for val in your array so it too is available to the caller. (with a slight change of type to size_t)
(another benefit of using size_t on platforms where size_t is larger than int is your array (or allocated block) can hold more than INT_MAX values and your code will still work without risk of integer overflow if a count exceeds what can be represented by an int)
Putting it altogether in a short example that creates an array of 100 elements holding random values from -10 to 10 and then chooses the value to find by choosing a random value in that range, you could check that all works as expected as follows:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NELEM 100 /* if you need a constant, #define one (or more) */
#define PERROW 10
#define LO_LIM -10
#define HI_LIM 10
int rand_in_range (int lowlim, int highlim)
{
return rand() % (highlim - lowlim + 1) + lowlim;
}
void arr_fill_rand (int *a, size_t nelem, int lowlim, int highlim)
{
for (size_t i = 0; i < nelem; i++)
a[i] = rand_in_range (lowlim, highlim);
}
void arr_prn (int *a, size_t nelem, const char* fmt)
{
const char *format = fmt != NULL ? fmt : " %d";
for (size_t i = 0; i < nelem; i++) {
if (i && i % PERROW == 0)
putchar ('\n');
printf (format, a[i]);
}
putchar ('\n');
}
size_t arr_occurrences (int *a, size_t nelem, size_t *first, int val)
{
int first_set = 0; /* flag if 1st occurrence set */
size_t occurs = 0; /* total no. of occurrences */
for (size_t i = 0; i < nelem; i++) { /* loop over each element */
if (a[i] == val) { /* is it equal to val? */
if (!first_set) { /* if first not set */
*first = i; /* update value at address of first */
first_set = 1; /* set first_set flag true */
}
occurs += 1; /* increment no. of occurrences */
}
}
return occurs; /* return total number of occurrences */
}
int main (void) {
int arr[NELEM] = {0}, /* array of NELEM set all zero */
val = 0; /* value to find */
size_t first = 0, /* index of first occurrence */
occurs = 0; /* total no. of occurrences */
srand (time(NULL)); /* seed random number generator */
val = rand_in_range (LO_LIM, HI_LIM); /* random in LO to HI (inclusive) */
arr_fill_rand (arr, NELEM, LO_LIM, HI_LIM); /* fill with random values in range */
arr_prn (arr, NELEM, " % 3d");
occurs = arr_occurrences (arr, NELEM, &first, val); /* get occurrences of val */
printf ("\n%d occurs first in array of %d " /* output results */
"elements ranging from %d to %d at:\n"
" index : %zu\n"
" address : %p\n"
"and occurs a total of %zu times.\n",
val, NELEM, LO_LIM, HI_LIM,
first, (void*)&arr[first], occurs);
}
(note: you never need more than one call to printf() (or fputs() or puts()) to provide on block of output, regardless of the number of lines it contains. You can keep things readable in longer output by breaking the string up into adjacent strings (newlines and other whitespace between them is ignored) and the compiler with create a single string to output from all adjacent string literals)
Example Use/Output
The program outputs the array and then outputs the results with the index of the first occurrence (and it's actual address if that is what you wanted) along with the total number of times the value of interest was found:
$ ./bin/arr_rand_1st_occ+count
3 -10 2 10 2 -9 4 5 -3 7
-4 -6 10 -4 8 -5 8 5 -10 10
10 6 -3 2 -5 1 1 8 10 -1
6 0 -1 -5 -1 10 -6 -10 4 1
5 -10 6 5 -4 1 8 -8 -4 8
-9 -7 2 -4 5 7 5 -7 3 4
2 -4 -6 10 1 1 9 5 0 0
-7 -6 -2 9 7 3 -2 4 3 4
2 4 5 -9 8 -3 6 2 0 -2
-6 -10 4 -2 8 -8 7 6 5 -4
8 occurs first in array of 100 elements ranging from -10 to 10 at:
index : 14
address : 0x7ffea2fb5938
and occurs a total of 7 times.
The array is output with 10 values PERROW to make things easier to read. Remember when confirming the results, arrays are zero-indexed in C.
Last note is unless you are programming in a freestanding environment (without the benefit of any OS), the allowable declarations for main for are int main (void) and int main (int argc, char *argv[]) (which you will see written with the equivalent char **argv). See: C11 Standard - §5.1.2.2.1 Program startup(p1). See also: What should main() return in C and C++?
In a freestanding environment (such as programming on a microcontroller) without the benefit of an operating-system, the name and type of the function called at program startup are implementation-defined. See: C11 Standard - 5.1.2.1 Freestanding environment
Look things over and let me know if you have further questions.
Your program behaviour is undefined because it end up dereferencing a NULL pointer here:
int *p = NULL;
int h[] = {1,2,3,4,5,1,1,3,4};
j = count(h, p , sizeof(h)/sizeof(int) , 1);
printf("%d %d", *p,j);
^^
|
Dereferencing p which is a NULL pointer
The way you are passing the p pointer from main() function to count() function, you are passing NULL. That means, in context of your program, this
j = count(h, p , sizeof(h)/sizeof(int) , 1);
is equivalent to this
j = count(h, NULL , sizeof(h)/sizeof(int) , 1);
The count() function parameter p will receive NULL as argument i.e. it's equivalent to p = NULL (where p is count() function parameter).
Whatever you assign to p in count() function, you are actually modifying a local variable of count() function. No changes are going to reflect in pointer variable p of main() function and it will remain a NULL pointer.
Now, lets come to the count() function.
In this snip of code of count() function:
for(int i=0; i<size ;i++)
{
if(h[i]==d && bool == 0)
{
j++;
bool = 1;
p = &i;
}
else if(h[i]==d)
j++;
}
the scope and life of loop variable i is within the for loop block. Once, the loop exit the lifetime of i is ended. JFYI - accessing an object outside of its lifetime is undefined behaviour. So, if p hold &i and out of loop body if your program access p then it will lead to undefined behaviour. Also, *p=-1; statement in count() will also lead to undefined behaviour because, in count() function p will be a NULL pointer if bool==0.
Remember, if a function is passing a pointer to another function as a argument and expecting that function to modify the value of pointer, which it receive as parameter, then the pointer should be pointing to a valid memory location before the calling function access and modify it's memory contents or the caller function should pass address of pointer as argument and let the calling function allocate memory dynamically to it so that it should be accessible from the caller function as well (which is main() function, in your case).
There are couple ways to achieve this.
Method I:
Pass a valid memory location to calling function.
Either pass address of a local variable of caller function as argument (this is same as your second code snippet)
int main (void) {
int j;
size_t res = 0;
size_t *p = &res; // p is pointing to res variable
int h[] = {1, 2, 3, 4, 5, 1, 1, 3, 4};
int num = 1;
j = count (h, p, sizeof (h) / sizeof (int), num);
if (j != -1) {
printf ("%zu %d", *p, j);
} else {
printf ("%d not found\n", num);
}
return 0;
}
Or allocate memory to pointer in caller function and pass it
int main (void)
{
int j;
size_t *p = NULL;
int h[] = {1, 2, 3, 4, 5, 1, 1, 3, 4};
int num = 1;
p = malloc (sizeof (size_t));
if (p == NULL) {
fprintf (stderr, "Failed to allocate memory");
exit (EXIT_FAILURE); // or whatever you want to do in case of allocation failure
}
j = count (h, p, sizeof (h) / sizeof (int), num);
if (j != -1) {
printf ("%zu %d", *p, j);
} else {
printf ("%d not found\n", num);
}
free(p);
return 0;
}
and the count() function implementation for both the above cases:
int count (int h[], size_t *p, size_t size, int d) {
int j = 0;
for (size_t i = 0; i < size ; ++i) {
if(h[i] == d) {
if (j == 0) {
*p = i;
}
++j;
}
}
return j == 0 ? -1 : j;
}
Method II:
Pass the address of p and dynamically allocate memory to p in count() function before accessing it. Note that, objects with allocated storage duration live until they are destroyed by a call to free(). So, if count() function allocates memory to a pointer, whose address passed as argument to count() function from main() function, then that memory will be accessible in main() function as well via pointer variable p.
#include <stdio.h>
#include <stdlib.h>
int count (int h[], size_t **p, size_t size, int d) {
int j = 0;
for(size_t i = 0; i < size ; ++i) {
if(h[i] == d) {
if ((j == 0) && (p != NULL)) {
*p = malloc (sizeof (size_t));
if (p == NULL) {
fprintf (stderr, "Failed to allocate memory");
exit (EXIT_FAILURE);
}
**p = i;
}
++j;
}
}
return j == 0 ? -1 : j;
}
int main (void) {
int retval;
size_t *p = NULL;
int h[] = {1, 2, 3, 4, 5, 1, 1, 3, 4};
int num = 3;
retval = count (h, &p, sizeof (h) / sizeof (int), num);
if (retval != -1) {
printf ("%zu %d\n", *p, retval);
} else {
printf ("%d not found\n", num);
}
// free memory once you are done with it
if (p != NULL) {
free (p);
}
return 0;
}
Additional:
Using void as return type of main function is not as per standards. The return type of main function should be int.
You are trying to return pointer pointing to a place which will be no longer valid once the loop completed it's execution, either declare i outside for or don't use the pointer part, as dereferencing a null pointer is illegal, also, you get segmentation fault when you try to access memory you have no business with and no permission to read or write, in this case, pointing to a memory location which is out of scope.
Instead of returning a pointer,simply create a local array of same type in the function, first index for first occurence of the given number, and second index for the total occurence, and return the array but make sure the return type should be pointer of same type.
edit: thanks Mr. Joshua, for pointing out the mistake.

How to use pointer to bidimensional array C

How do I edit a value in an array with pointer in C?
int *pointer;
int array[3][1];
I tried this:
int *Pointer
int array[2][2];
Pointer[1][1]= 6;
but when compiling, I get a segmentation fault error. What to do?
Given some array int Array[Rows][Columns], to make a pointer to a specific element Array[r][c] in it, define int *Pointer = &Array[r][c];.
Then you may access that element using *Pointer in an expression, including assigning to *Pointer to assign values to that element. You may also refer to the element as Pointer[0], and you may refer to other elements in the same row as Pointer[y], where y is such that 0 ≤ y+c < Columns, i.e., Pointer[y] remains in the same row of the array.
You may also use Pointer[y] to refer to elements of the array in other rows as long as none of the language lawyers see you doing it. (In other words, this behavior is technically not defined by the C standard, but many compilers allow it.) E.g., after Pointer = &Array[r][c];, Pointer[2*Columns+3] will refer to the element Array[r+2][c+3].
To make a pointer you can use to access elements of the array using two dimensions, define int (*Pointer)[Columns] = &Array[r];.
Then Pointer[x][y] will refer to element Array[r+x][y]. In particularly, after int (*Pointer)[Columns] = &Array[0]; or int (*Pointer)[Columns] = Array;, Pointer[x][y] and Array[x][y] will refer to the same element.
You can access any given element with this syntax: array[x][y].
By the same token, you can assign your pointer to any element with this syntax: p = &array[x][y].
In C, you can often treat arrays and pointers as "equivalent". Here is a good explanation:
https://eli.thegreenplace.net/2009/10/21/are-pointers-and-arrays-equivalent-in-c
However, you cannot treat a simple pointer as a 2-d array. Here's a code example:
/*
* Sample output:
*
* array=0x7ffc463d0860
* 1 2 3
* 4 5 6
* 7 8 9
* p=0x7ffc463d0860
* 0x7ffc463d0864:1 0x7ffc463d0868:2 0x7ffc463d086c:3
* 0x7ffc463d0870:4 0x7ffc463d0874:5 0x7ffc463d0878:6
* 0x7ffc463d087c:7 0x7ffc463d0880:8 0x7ffc463d0884:9
*/
#include <stdio.h>
int main()
{
int i, j, *p;
int array[3][3] = {
{1,2,3},
{4,5,6},
{7,8,9}
};
// Dereference 2-D array using indexes
printf("array=%p\n", array);
for (i=0; i < 3; i++) {
for (j=0; j < 3; j++)
printf ("%d ", array[i][j]);
printf ("\n");
}
// Dereference 2-D array using pointer
p = &array[0][0];
printf("p=%p\n", p);
for (i=0; i < 3; i++) {
for (j=0; j < 3; j++)
printf ("%p:%d ", p, *p++);
printf ("\n");
}
/* Compile error: subscripted value p[0][0] is neither array nor pointer nor vector
p = &array[0][0];
printf("p=%p, p[0]=%p, p[0][0]=%p\n", p, &p[0], &p[0][0]);
*/
return 0;
}
Cast the 2D-array into 1D-array to pass it to a pointer,
And then, You are ready to access array with pointer. You can use this method to pass 2D-array to a function too.
#include <stdio.h>
int main()
{
int arr[2][2];
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
arr[i][j] = (2 * i) + j;
}
}
int *Pointer = (int *)arr; // Type conversion
/*
&arr[0][0] = Pointer + 0
&arr[0][1] = Pointer + 1
&arr[1][2] = Pointer + 2
&arr[2][2] = Pointer + 3
Dereference Pointer to access variable behind the address
*(Pointer + 0) = arr[0][0]
*(Pointer + 1) = arr[0][1]
*(Pointer + 2) = arr[1][2]
*(Pointer + 3) = arr[2][2]
*/
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
printf("%d ", *(Pointer + (2 * i) + j)); // Accessing array with pointer
}
printf("\n");
}
return 0;
}
Using the function wv_matalloc from https://www.ratrabbit.nl/ratrabbit/content/sw/matalloc/introduction , you can write the following code:
#include <stdio.h>
#include "wv_matalloc.h"
int main()
{
double **matrix;
int m = 3;
int n = 4;
// allocate m*n matrix:
matrix = wv_matalloc(sizeof(double),0,2,m,n);
// example of usage:
int i,j;
for (i=0; i<m; i++)
for (j=0; j<n; j++)
matrix[i][j] = i*j;
printf("2 3: %f\n",matrix[2][3]);
}
Compile with:
cc -o main main.c wv_matalloc.c
1.
You never assigned a value to Pointer in your example. Thus, attempting to access array by Pointer invokes undefined behavior.
You need to assign Pointer by the address of the first element of array if the pointer shall be a reference:
Pointer = *array;
2.
You can't use 2D notation (p[1][1]) for a pointer to int. This is a C syntax violation.
3.
Since rows of static 2D arrays are allocated subsequent in memory, you also can count the number of array elements until the specific element of desire. You need to subtract the count by 1 since indexing start at 0, not 1.
How does it work?
Each row of array contains 2 elements. a[1][1] (the first element of the second row) is directly stored after the first two.
Note: This is not the best approach. But worth a note beside all other answers as possible solution.
#include <stdio.h>
int main (void)
{
int *Pointer;
static int array[2][2];
Pointer = *array;
Pointer[2] = 6;
printf("array[1][1] (by pointer) = %d\n", Pointer[3]);
printf("array[1][1] (by array istelf) = %d\n", array[1][1]);
}
Output:
array[2][2] (by pointer) = 6
array[2][2] (by array istelf) = 6
Side Notes:
To address the first element of the second row by array[1][2] invokes undefined behavior. You should not use this way.
"but when compiling, I get a segmentation fault error."
Segmentation fault error do not occur at compile time. They occur at run time. It just gives you the impression because high probably your implementation immediately executes the program after compilation.

C, Why the function doesn't accept the 2d-array from txt file as an argument?

This is my C code and and .txt file. I want to use 2d-array from .txt file as a function argument. However, when I run this code, program gives error at the call function lines such:
[Error] cannot convert 'int (*)[C]' to 'int (*)[3]' for argument '1' to 'int rec_ped(int (*)[3], int)'.
Other words, my function rec_ped cannot accept the 2d-array from .txt file.
Could you help me about this?
#include <stdio.h>
int rec_ped(int k[18][3], int idx) {
int sire, dam;
sire = k[idx - 1][1];
dam = k[idx - 1][2];
printf("%d ", sire);
if (sire != 0)
rec_ped(k, sire);
if (dam != 0)
rec_ped(k, dam);
}
int main() {
int R = 18;
int C = 3;
int A[R][C];
FILE *fp;
int i, j;
fp = fopen("t.txt", "r");
for (i = 0; i < R; i++) {
for (j = 0; j < C; j++) {
fscanf(fp, "%d", &A[i][j]);
}
}
for (i = 0; i < R; i++) {
for (j = 0; j < C; j++) {
A[i][j];
rec_ped(A, 18); // <--- there is error!!!
}
}
return 0;
}
my file is a.txt as below;
1 0 0
2 0 0
3 0 0
4 0 0
5 0 0
6 1 3
7 1 5
8 0 2
9 4 6
10 0 0
11 1 0
12 4 10
13 7 11
14 1 6
15 13 0
16 1 15
17 4 14
18 16 17
When an array decays to a pointer, it only applies to the outermost array dimension. It does not apply to inner dimensions. So int (*)[3] and int (*)[C] are not the same, even though C happens to be 3 at the time the function is called. A fixed size array and a variable length array can't be considered the same in this situation.
What you can do however is pass the dimensions of an array as parameters:
int rec_ped(int rows, int cols, int k[rows][cols], int idx) {
Then you can call it like this:
rec_ped(R, C, A, 18);
Make C a constant (#define C 3)!
Problem is: Without C being constant, but a variable, it could have been modified before declaring the array, so the latter actually is a VLA. The function, in contrast, expects a fixed size array, so types don't match.
Be aware you don't have to make R constant:
int rec_ped(int k[18][3], int idx);
is equivalent to
int rec_ped(int k[][3], int idx);
which is equivalent to
int rec_ped(int (*k)[3], int idx);
i. e. the function actually accepts a pointer to an array of length 3 just like void f(int*); accepts a pointer to int. In both cases, the pointer could reference the first element of an array (array of array or array of int respectively) or just a single element...

Using pointers to matrices in a scanf function

I was playing around with pointers when inputing a matrix with scanf and for some reason, when I run this code, only the first element of every row gets stored correctly.
#include "stdio.h"
void main()
{
int i, j, n, A[10][10];
scanf("%d", &n);
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
scanf("%d", A + j + i*10);
}
This is what I get after inputing 1,2,3,4,5,6,7,9 into a 3x3 matrix and printing it:
1 -858993460 -858993460
2 -858993460 -858993460
3 -858993460 -858993460
According to my understanding of how matrices are stored, this should work. Can anyone point out whats wrong with my code?
You declare A as
int A[10][10];
that is, an array of 10 arrays of 10 ints each. Thus, when A decays to a pointer to its first element, the type of that pointer is int (*)[10]. That's a pointer to an array of 10 ints, not a pointer to a single int. Among the differences is their interaction with pointer arithmetic. Because pointer arithmetic is defined in terms of the size of the pointed-to type, whenever i is nonzero, the expression A + j + i*10 produces a pointer (to array of 10 ints) outside the bounds of array A.
The most type-safe way of doing what you want would be to use array syntax to select array elements:
&A[i][j]
. Type-correct alternatives that use pointer arithmetic include
&(*(A + i))[j]
and
*(A + i) + j
These latter two both rely on the fact that the expression A + i is a pointer to an array of int; dereferencing that pointer produces an array, which can be the operand of the [] operator (and the address of the result then taken). Alternatively, the array designated by *(A + i) decays to a pointer to its first element (i.e. decays to an int *) when it appears as an operand of the + operator, and adding j to that yields a pointer to the jth element of array *(A + i) (which is the same array designated by A[i]).
Bad pointer math.
A + j + i * 10
When A is used in A + j + i*10, it becomes the pointer to its first element, which is an array of 10 int. Every 1 added to A offsets its address by 40 bytes.
Recommend to use &A[i][j] instead.
Code re-worked to show addresses used.
#include "stdio.h"
int main() {
int i, j, n, A[10][10];
n = 3;
char *base = (char*) A;
for (i = 0; i < n; i++)
for (j = 0; j < n; j++) {
char *offset0 = (char*) (&A[i][j]);
char *offset1 = (char *) (A + j + i * 10);
printf("%d %d %3td %3td\n", i, j, offset0 - base, offset1 - base);
}
}
Output
0 0 0 0
0 1 4 40
0 2 8 80
1 0 40 400
1 1 44 440
1 2 48 480
2 0 80 800
2 1 84 840
2 2 88 880

Integer Pointer Array

I have started an introductory class to C. I cannot explain the output that I get from running the code below
./a.out 6
Output is:
Array A elements: 0 1 2 3 4 5
Array B elements: 1 2 3 4 5 796830176
What I think the code is doing:
When manup_array is executed, each value of the respective pointers will be incremented, but since it is post-fix, this takes effect only later on after the original value is returned.
True enough, when we print array A first, we get 0 1 2 3 4 5 (i.e. before incrementation).
Subsequently when we print array B, the incrementation takes effect, so we get 1 2 3 [...]
What really puzzles me is why the last number is 796830176. Also, running this on various computers produces a different last number every time, suggesting that the pointer addressing is somehow responsible for this.
Could someone explain this to me?
Note:
The outputs of each array are identical (1 2 3 4 5 6) if I use the pre-fix operator. This is consistent with what I think is going on -> the pointers don't change; only the values get updated.
#include <stdio.h>
#include <stdlib.h>
void manup_array(int *array[], int n); // Forward declaration.
int main(int argc, char *argv[])
{
// The size N of 2 arrays are the same; obtain them from cmd line.
int N = atoi(argv[1]); // Convert from str to int in C.
int arrayA[N]; // Declare integer array.
int *arrayB[N]; // Declare integer pointer array.
for (int i = 0; i < N; i++)
{
arrayA[i] = i;
arrayB[i] = &arrayA[i]; // Assign address of each element in A to element in B.
}
manup_array(arrayB, N);
printf("Array A elements: ");
for (int i = 0; i < N; i++)
{
printf("%d ", arrayA[i]);
}
printf("\n");
printf("Array B elements: ");
for (int i = 0; i < N; i++)
{
printf("%d ", *arrayB[i]);
}
printf("\n");
return 0;
}
void manup_array(int *array[], int n) { // Take in B as input, then increase each elem by 1
for (int i = 0; i < n; i++)
{
*array[i]++;
}
}
This is really obscure code. What is does:
The function takes an array of pointers as parameter. Since the parameter to the function had type int *array[], any change of the items of array will affect the caller and alter arrayB.
The interesting part of the function is *array[i]++;. The operator precedence rules in C state that [] has higher prio than postfix ++, which has higher prio than unary *.
Since array is an array of pointers, array[i] gives you a pointer. Not a the value it points at. Then ++ increments the pointer to point at the next item in the arrayA of main.
And then finally there is a * which takes the contents of what that pointer pointed at, and then does nothing with them. The * is superfluous and just there to confuse the reader.
So back in main, you have changed all the pointers of arrayB. arrayB[0] now points at arrayA[1] and so on. The last item of arrayB will point one item past the end of arrayA, so for the last item, you access the array out-of-bounds and get a garbage value.
void manup_array(int *arr[], int n) { // Take in B as input, then increase each elem by 1
for (int i = 0; i < n; i++)
{
int val = (*arr[0]); // get the value pointed to by the current value of arr
val++; // increment it
*(arr[0]) = val; // assign it back
arr++; // increase the pointer
}
}
Incredibly obtuse, but it demonstrates what you mean to do and how your obscure code muddled up the operators.
To add, makes debugging way easier!
manup_array() increments the pointer, not the value as expected.
Modified manup_array().
void manup_array(int *array[], int n) { // Take in B as input, then increase each elem by 1
for (int i = 0; i < n; i++)
{
//*array[i]++;
(*array[i])++;
}
}
I suggest to refer Pointer Arithmetic: ++*ptr or *ptr++?

Resources