Function Parameter Changes in C - c

i've tried searching for the answer/ looking at the C library for pointers, but wasn't sure on the right solution. My question concerns changing the parameters of a function. I've been reading on pointers/functions, and from my understanding, if a function takes in (int x1), then when the function is done with x1, x1 outside the function remains untouched. However, if you pass in a int *x1, then it is changed.
I've been experimenting with it, and i've tried using this with a sort method...
void sorting(int *arr, int size) {
int *i, *j, temp;
int *len = arr + size - 1;
for(i = arr; i < len; i++) {
for(j = i + 1; j <= len; j++) {
if(*j < *i) {
temp = *i;
*i = *j;
*j = temp;
}
}
}
int k;
for(k = 0; k < size; k++) {
printf("k: %d, arr[k]: %d \n", k, *(arr + k));
}
}
What this would print is a fully sorted list. However, in my main function, if I called this...
int main() {
int temp[5] = {0, 2, 1, 3, 1};
int *p = &temp[5];
sorting(pa, 5);
print the values of pa...
}
Then the list remains unsorted if printing out the values of pa.
If this question has already been solved, could someone please link the question, and i'll delete the post.

You're accessing the array out of bounds here:
int *p = &temp[5];
The valid indices are [0, 5). Presumably you want a pointer to the first element:
int *p = &temp[0];
But note that you can pass an array to a function that expects a pointer. In this case the array decays to a pointer to the first element:
sorting(temp, 5);

Related

C - Passing an array between functions gets different values

So I'm trying to write a function that'll search a word in a 2D bulk.
The function returns an (int) array of size [3] with values as the answer.
Here is my main() function:
void main() {
char bulk[L][L];
for (int i = 0; i < L; i++) {
for (int j = 0;j < L;j++)
scanf_s(" %c", &bulk[i][j]);
}
int *arr = search(&bulk, L, "bc");
printf("ARR: %d, %d, %d\n", arr[0], arr[1], arr[2]);
}
And here's the search() function:
int *search(char(*bulk)[L], int size, char *word) {
int arr[3] = { 0,0,0 };
int flag = 9;
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
if (bulk[i][j] == *word) {
if (checkRight(bulk, i, j, word)) flag=0;
}
if (flag != 9) {
arr[0] = i;
arr[1] = j;
arr[2] = flag;
printf("ARR: %d, %d, %d\n", arr[0], arr[1], arr[2]);
return arr;
}
}
}
return arr;
}
The checkRight() function works well, it returns 0/1 for if the word exists to the right. The problem is that the two printf's are printing different values.
Output for search(): "ARR: 0,1,0".
Output for main(): "ARR: -858993460, -858993460, 0".
I assume it's pointer-related but I'm struggling with finding the problem. Any ideas?
Thanks a bunch!
return arr;
In here you are returning the address of the first value in the array, this address points to a temporary value inside the stack frame of the function search.
try to pass arr as a parameter or using "static int arr[3]" in order to make the array not temporary.

Function that return a structure that contains a pointer to array in C

First few parts of code:
typedef struct
{
double sr, med;
int **t;
}wynik;
wynik calc(int *t[], int size)
{
int i, *niep = NULL, j = 0, k = 1, sum = 0;
int *sorted = (int*)malloc(size*sizeof(int));
wynik out;
//coping, sorting
for (i = 0; i < size; i++)
sorted[i] = (*t)[i];
qsort(sorted, size, sizeof (**t), cmp);
out.t = &sorted;
...
return out;
}
then in main():
wynik get = calc(&tab, tab_size);
Using debugger I discovered that in calc() out.t points to an array, but in main() get.t points to some weird things.
How to fix it?
out.t contains the address of the local variable sorted. When the function returns, this address is no longer valid because the local variable went out of scope.
I see no reason here that out.t should be int** instead of int*. If you change it to be int* and just set its value with out.t = sorted, it should work correctly.

int** vs int[const][const] differences

I was writing a code the other day and I found it rather strange, that int** and int[][] does not behave the same way. Can anyone point out the differences between them? Below is my sample code, which fails with a segmentation fault, if I pass constant size 2d array, while it does work fine when I pass a dinamically allocated 2d array.
I am confused mainly because ant int[] array works the same as int*.
#include<stdio.h>
#include<stdlib.h>
void sort_by_first_row(int **t, int n, int m)
{
int i, j;
for(i = m-1 ; i > 0 ; --i)
{
for(j = 0 ; j < i; ++j)
{
if(t[0][j] < t[0][j+1])
{
int k;
for(k = 0 ; k < n ;++k)
{
int swap;
swap = t[k][j];
t[k][j] = t[k][j+1];
t[k][j+1] = swap;
}
}
}
}
}
int main(void) {
int i, j;
/* Working version */
/*int **t;
t =(int**) malloc(3*sizeof(int*));
for(i = 0; i < 3; ++i)
{
t[i] = (int*) malloc(6*sizeof(int));
}*/
/*WRONG*/
int t[3][6];
t[0][0] = 121;
t[0][1] = 85;
t[0][2] = 54;
t[0][3] = 89;
t[0][4] = 879;
t[0][5] = 11;
for( i = 0; i < 6; ++i )
t[1][i] = i+1;
t[2][0] = 2;
t[2][1] = 4;
t[2][2] = 5;
t[2][3] = 3;
t[2][4] = 1;
t[2][5] = 6;
sort_by_first_row(t, 3, 6);
for(i = 0; i < 3; ++i)
{
for(j = 0; j < 6; ++j)
printf("%d ", t[i][j]);
printf("\n");
}
return 0;
}
So based on the below answers I realize, that a multidimensional array is stored continuously in a row major order. After some modification, the below code works:
#include<stdio.h>
#include<stdlib.h>
void sort_by_first_row(int *t, int n, int m)
{
int i, j;
for(i = m-1 ; i > 0 ; --i)
{
for(j = 0 ; j < i; ++j)
{
if(t[j] < t[j+1])
{
int k;
for(k = 0 ; k < n ;++k)
{
int swap;
swap = t[k*m + j];
t[k*m + j] = t[k*m + j+1];
t[k*m + j+1] = swap;
}
}
}
}
}
int main(void) {
int i, j;
/* Working version */
/*int **t;
t =(int**) malloc(3*sizeof(int*));
for(i = 0; i < 3; ++i)
{
t[i] = (int*) malloc(6*sizeof(int));
}*/
/*WRONG*/
int t[3][6];
t[0][0] = 121;
t[0][1] = 85;
t[0][2] = 54;
t[0][3] = 89;
t[0][4] = 879;
t[0][5] = 11;
for( i = 0; i < 6; ++i )
t[1][i] = i+1;
t[2][0] = 2;
t[2][1] = 4;
t[2][2] = 5;
t[2][3] = 3;
t[2][4] = 1;
t[2][5] = 6;
sort_by_first_row(t, 3, 6);
for(i = 0; i < 3; ++i)
{
for(j = 0; j < 6; ++j)
printf("%d ", t[i][j]);
printf("\n");
}
return 0;
}
My new question is this: How to modify the code, so that the procedure works with int[][] and int** also?
Realize that int **t makes t a pointer to a pointer, while int t[3][6] makes t an array of an array. In most cases, when an array is used in an expression, it will become the value of the address of its first member. So, for int t[3][6], when t is passed to a function, the function will actually be getting the value of &t[0], which has type pointer to an array (in this case, int (*)[6]).
The type of what is being pointed at is important for how the pointer behaves when indexed. When a pointer to an object is incremented by 5, it points to the 5th object following the current object. Thus, for int **t, t + 5 will point to the 5th pointer, while for int (*t)[M], t + 5 will point to the 5th array. That is, the result of t + 5 is the same as the result of &t[5].
In your case, you have implemented void sort_by_first_row(int **t, int n, int m), but you are passing it an incompatible pointer. That is, the type of &t[0] (which is what t will become in main) is not the same as what the function wants, a int **t. Thus, when the sorting function starts to use that address, it will think its indexing into pointers, when the underlying structure is an array of arrays.
int** is quite different from int[][]. int** is simply a pointer to a pointer and would appear like the following:
in reality, you can access the entire multidimensional array with simply int* pointing to the first element, and doing simple math from that.
Here is the result of the separate allocations (in your commented code):
However when you allocate a multidimensional array, all of the memory is contiguous, and therefore easy to do simple math to reach the desired element.
int t[3][6];
int *t = (int*) malloc((3 * 6) * sizeof(int)); // <-- similarly
This will result in a contiguous chunk of memory for all elements.
You certainly can use the separate allocations, however you will need to walk the memory differently.
Hope this helps.
int t[3][6] is very nearly the same thing as int t[18]. A single contiguous block of 18 integers is allocated in both cases. The variable t provides the address of the start of this block of integers, just like the one-dimensional case.
Contrast this with the case you have marked as "working", where t gives you the address of a block of 3 pointers, each of which points to a block of memory with 6 integers. It's a totally different animal.
The difference between t[3][6] and t[18] is that the compiler remembers the size of each dimension of the array, and automatically converts 2D indices into 1D offsets. For example, the compiler automatically converts t[1][2] into *(t + 1*6 + 2) (equivalent to t[8] if it were declared as a one-dimensional array).
When you pass a multi-dimensional array to a function, there are two ways to handle it. The first is to declare the function argument as an array with known dimension sizes. The second is to treat your array like a 1D array.
If you are going to declare the size of your array, you would declare your function like this:
void sort_by_first_row(int t[][6], int n)
or this
void sort_by_first_row(int t[3][6])
You either have to declare all array dimension sizes, or you can leave out the first size. In both cases, you access elements of t using t[i][j]; you've given the compiler enough information to do the offset math that converts from 2D notation to a 1D index offset.
If you treat it as a 1D array, you have to pass the array dimensions and then do the offset math yourself.
Here's a full working example, where f and f2 both generate the same output:
void f(int* t, int m, int n)
{
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
std::cout << t[i * n + j] << " ";
std::cout << std::endl;
}
void f2(int t[][6], int m)
{
for (int i = 0; i < m; i++)
for (int j = 0; j < 6; j++)
std::cout << t[i][j] << " ";
std::cout << std::endl;
}
int main()
{
int t[3][6];
int val = 1;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 6; j++)
{
t[i][j] = val;
val++;
}
}
f(&(t[0][0]), 3, 6);
f2(t, 3);
return 0;
}
One thing to note is the hack-ish way I had to pass t to f. It's been a while since I wrote in C/C++, but I remember being able to pass t directly. Maybe somebody can fill me in on why my current compiler won't let me.
A int ** is a pointer to a pointer to an int, and can be a pointer to an array of pointers to arrays of ints. A int [][] is a 2-dimensional array of ints. A two-dimensional array is exactly the same as a one-dimensional array in C in one respect: It is fundamentally a pointer to the first object. The only difference is the accessing, a two-dimensional array is accessed with two different strides simultaneously.
Long story short, a int[][] is closer to an int* than an int**.

i m unable to know the use of (int *)

I'm unable to know why do we have to use typecasting (int *) in case of 2d array?
another thing I want to know is that why can't we use *(*(p+i)+j)) to access the 2d array in following code? Is it always necessary to use p + col*i + j? Why can't I use *(*(p+i)+j)) when p contains base address of array and *(*(p+i)+j)) is equivalent to a[i][j]?
Thank you in advance.
main()
{
int a[3][4] = {
1,2,3,4,
5,6,7,8,
9,0,1,6
};
int *p,i,j;
p=(int *)a; // this is my doubt why did we use int *
for(i=0;i<3;i++)
{
for(j=0;j<4;j++) {
printf("%d",*(*(p+i)+j)); // here is my 2nd doubt
}
}
}
The code you provided does not compile because of line:
printf("%d",*(*(p+i)+j));
where you are dereferencing twice an int*
You can create a pointer to reference the array a of type pointer to array of 4 elements.
See the attached code where are all pointers are printed out during the execution of the nested for loop.
#include<stdio.h>
main()
{
int a[3][4]={
1,2,3,4,
5,6,7,8,
9,0,1,6
};
int (*p)[4],i,j;
p = a;
for(i=0;i<3;i++){
printf("row pointer: %p\n",p+i);
for(j=0;j<4;j++){
printf("element pointer: %p\n", (*(p+i))+j );
printf("element: %d\n",*( (*(p+i)) + j ) );
}
}
}
Your code does not even compile, exactly where your 2nd place of doubt is. I've corrected it:
#include <stdio.h>
int main(int argc, char *argv[])
{
int a[3][4] = {
1,2,3,4,
5,6,7,8,
9,0,1,6,
};
int *p, i, j;
p = a[0]; // No cast, just address the 1st row
for (i = 0; i < 3; i++) {
for (j = 0; j < 4; j++) {
printf("%d", *(p + 4*i + j)); // corrected pointer arithmetic
}
}
}
Pointer p does not know it's addressing a 2-dim array, it's just an int pointer.
Are you sure you want to print the numbers without even separating them by whitespace?

Problems with implementation of concatenation function in C

I am still new to pointers in C and have been trying to make string functions. This one is supposed to concatenate two strings, but when I try to run it, it crashes.
void concatenate (char *a, char *b, int size_a, int size_b) {
char *c, *d, *e;
c = a;
d = b;
int i, j, k;
int l = 1;
for(i = 0; i<size_a; i++) {
*(e+i) = *(c+i);
}
for (j = size_a; j<size_a+size_b; j++) {
*(e+j) = *(d+(j-(j-l)));
l++;
}
for (k = 0; k< size_a+size_b; k++){
printf("%c",*(e+k));
}
}
What am I doing wrong?
You are trying to access the memory where uninitialized pointer e points to, which leads to undefined behavior.
Your function should look like this:
char* concatenate (const char *a, const char *b, int size_a, int size_b) {
// create new string:
char* newStr = malloc (size_a + size_b + 1);
int i, j;
// copy first string into it:
for (i = 0; i<size_a; i++)
newStr[i] = a[i];
// copy second string into it:
for (j = 0; j < size_b; j++)
newStr[i + j] = b[j];
newStr[i + j] = '\0';
return newStr;
}
Note that function doesn't change strings that are passed to it, thus they can be passed as const. The size_a and size_b are expected to be equal to strlen(a) and strlen(b), which also means that in case you always pass null-terminated strings into this function, you can calculate their length on your own within its body (so you can get rid of last 2 arguments).
e is an uninitialized pointer, which means it is pointing to some random place in memory. When you start writing to it as if it were a pointer to a character array, your program will crash (or worse, change some state mysteriously causing unspecified behavior later on).
Your code seems obfuscated for no reason. The problem is that you're assigning to e, which is uninitialized. The following is, pretty much, your code in a more readable form and with e allocated. I haven't tested it, though.
void concatenate (char *c, char *d) {
char *e;
e = calloc(strlen(c) + strlen(d) + 1, sizeof(char));
int i, j;
int l = 1;
for(i = 0; c[i]; i++) {
e[i] = c[i];
}
l = i;
for (j = 0; d[j]; j++) {
e[l + j] = d[j];
}
e[l + j] = '\0';
printf("%s", e);
free(e);
}

Resources