correct way to change values of c pointers - c

Sorry, another C pointer question.. I have a function func() that sorts an array, then get the largest and smallest integers. I'm trying to put them inside pointer variables in main() but the values are only correct inside the func() function. I don't understand why :(
#include <stdio.h>
void func(int arr[], int *s, int *l, int n){
int i = 1;
for(; i < n; i++){
int temp = arr[i];
int n = i;
while( n > 0 && arr[n-1] > temp){
arr[n] = arr[n-1];
n--;
}
arr[n] = temp;
}
l = &arr[n-1];
s = &arr[0];\
printf("%d %d\n",*l,*s);
}
int main(void){
int arr[] = {1,2,9,3,58,21,4};
int *s, *l;
int size = 7;
func(arr,s,l,size);
printf("%d %d\n",*l,*s);
}

When you pass a pointer as an argument to a function in C, a copy of the pointer is made. Thus, changing the value of the pointer has no effect outside of that function. However, changing the value at the memory referenced by the pointer will take effect everywhere, as you want. In your case, you would need to do this:
void func(int arr[], int *s, int *l, int n){
// sorting code..
// l = &arr[n-1]; WRONG - these change the value of the pointer,
//s = &arr[0];\ without changing the value of the memory they reference
*l = arr[n-1]; // CORRECT - changes the value at the referenced memory
*s = arr[0];
printf("%d %d\n",*l,*s);
}
Of course, the way you're using the pointers in main is also incorrect; they're uninitialized and likely to cause a segmentation fault. Since there appears to be no reason to use actual int* variables over ordinary int variables there, we can take another approach to passing them "by reference":
int main(void){
int arr[] = {1,2,9,3,58,21,4};
// int *s, *l; WRONG - we don't need pointers, we need to pass regular ints
int s, l;
int size = 7;
// Get the address of our variables with the address-of (&) operator
// This effectively creates int* variables out of our int variables
func(arr, &s, &l,size);
printf("%d %d\n",*l,*s);
}
Note that the term "by reference" here is not correct in the true sense of the phrase, since you are still receiving a copy of the address associated with the variable. Most languages provide a true by-reference faculty by removing this distinction and only allowing you access to the variable and its value, with the copying somewhat out of sight of the programmer. You can think of this as being "by reference with respect to l and s inside main", in the sense that their values can change due to the called function.

You need to pass the address of the pointer variables if you want to change what they are pointing at, otherwise a copy of the pointer variable is being changed inside the function (and is why it is correct within the function):
void func(int arr[], int** s, int** l, int n){
/* snip */
*l = &arr[n-1];
*s = &arr[0];
}
func(arr, &s, &l, size);
This would leave s and l pointing to elements of the array arr. If you just wanted the values of integers then the alternative would be to define int variables in main() and pass their addresses to func() and copy the relevent values from the array:
void func(int arr[], int* s, int* l, int n){
/* snip */
*l = arr[n-1];
*s = arr[0];
}
int s, l;
func(arr, &s, &l, size);
See this question from the C FAQ.

Your pointers are not initialized. You have two solutions:
use integers in main function (and eventually, although useless, make pointers point to them in the same function);
dynamically allocate memory for your pointer.
Easiest code:
#include <stdio.h>
int main(void)
{
int arr[] = {1, 2, 9, 3, 58, 21, 4};
int s, l;
int size = 7;
func(arr, &s, &l, size);
printf("%d %d\n", l, s);
}
In the current code, you don't need to make l and s point to the case of the array. So, as Dan F stated, you can just do integer's assignment.
void func(int arr[], int *s, int *l, int n)
{
int i = 1;
for(; i < n; i++){
int temp = arr[i];
int n = i;
while( n > 0 && arr[n-1] > temp){
arr[n] = arr[n-1];
n--;
}
arr[n] = temp;
}
*l = arr[n-1];
*s = arr[0];
printf("%d %d\n", *l, *s);
}

Related

Passing array of structs with reference - segmentation fault

#include <stdio.h>
#include <stdlib.h>
struct X {
char surname[30];
int deg;
};
void read_record(struct X** a, int size){
for (int i = 0;i < size; i++){
a[i]->deg = 0;
}
}
int main(){
int n = 10;
struct X *container = (struct X*)malloc(sizeof(struct X) * n);
read_record(&container, n);
}
I created a 1D array of size n, then I passed it by reference to the function read_record. However, when I execute the program, there is a segmentation fault. What is the problem?
EDIT:
As a next step, I want to reallocate the array of 10 elements in the function with size of 20. That's why I want to send the array as a reference. If I did it in main then I would write:
container = realloc(container, (n + 10) * sizeof(Struct X));
How can I do this in the function?
container is already a pointer, you don't need to pass the address-of the pointer, instead:
#include <stdio.h>
#include <stdlib.h>
struct X {
char surname[30];
int deg;
};
void read_record(struct X *a, size_t size)
{
for (size_t i = 0; i < size; i++) {
a[i].deg = 0;
}
}
int main(void)
{
size_t n = 10;
struct X *container = malloc(sizeof(struct X) * n);
read_record(container, n);
}
also, prefer size_t to store the number of allocated objects.
Nitpick: read_record doesn't seem a good name for a function that modifies the contents of the records.
EDIT: As a next step, I want to reallocate the array of 10 elements in the function with size of 20. (in the function). That's why I want to send the array as a reference.
Same approach but returning a reallocated container:
#include <stdio.h>
#include <stdlib.h>
struct X {
char surname[30];
int deg;
};
struct X *read_record(struct X *a, size_t size)
{
struct X *new = realloc(a, sizeof(struct X) * size);
if (new != NULL)
{
for (size_t i = 0; i < size; i++) {
new[i].deg = 0;
}
}
return new;
}
int main(void)
{
size_t n = 10;
struct X *container = malloc(sizeof(struct X) * n);
container = read_record(container, n * 2);
if (container == NULL)
{
fprintf(stderr, "Can't read record\n");
exit(EXIT_FAILURE);
}
}
As a next step, I want to reallocate the array of 10 elements in the function with size of 20. (in the function). That's why I want to send the array as a reference.
The pointer is passed by value, so to save the changes and have them usable outside the function scope, after the function ends, i.e. in main, a pointer to pointer must be the argument, and the address of the pointer must be passed, your overall assessment is correct.
Your implementation, however, is not correct, here's how you shoud do it:
Live demo
void read_record(struct X **a, int size) //double pointer
{
*a = realloc(*a, sizeof **a * (size + 10)); //reallocate memory for 20 ints
if (*a == NULL)
{
perror("malloc");
}
for (int i = 0; i < size + 10; i++) //assing new values
{
(*a)[i].deg = 1;
}
}
int main()
{
int n = 10;
struct X *container = malloc(sizeof *container * n); //original allocation
//the pointer now has space for 10 ints
if (container == NULL)
{ //check allocation errors
perror("malloc");
}
for (int i = 0; i < n; i++) //assign values
{
container[i].deg = 0;
}
read_record(&container, n); //pass by reference
//the pointer now has space for 20 ints
}
Alternatively you can return the pointer instead, refering to David Ranieri's answer.
The first function parameter has the pointer to pointer type struct X**. So dereferencing the parameter a you will get a pointer of the type struct X*. Now you may apply the subscript operator that yields lvalue of the type struct X..
That is the function definition will look like
void read_record(struct X** a,int size){
for (int i=0;i<size;i++){
( *a )[i].deg = 0;
}
}
Or this statement
( *a )[i].deg = 0;
may be substituted for this statement
a[0][i].deg = 0;
On the other hand, there is no great sense to declare the first parameter as having the type struct X**. The function can look simpler as for example
void read_record(struct X* a,int size){
for (int i=0;i<size;i++){
a[i].deg = 0;
}
}
and be called like
read_record( container, n );
When you call read_record you pass a pointer to a pointer to the first element of an array of X structures.
But inside the read_record you treat it as a pointer to the first element of an array of pointers to X structures (i.e. as an array of pointers to X). There's a subtle but very important difference here.
If you want to emulate pass-by-reference for the pointer variable, you need to dereference it inside the read_record to get the original pointer (and remember that then you have an array of objects, not pointers):
(*a)[i].deg = 0;
Double pointer is the problem. The code should be:
void read_record(struct X* a,int size){ // Check the change
for (int i=0;i<size;i++){
a[i]->deg = 0;
}
}
int main(){
int n = 10;
struct X *container=(struct X*)malloc(sizeof(struct X)*n);
read_record(container,n); // Check the change
}

Generic swap function using pointer to char in C

I don't understand so well how this code works:
#include <stdio.h>
void gswap(void* ptra, void* ptrb, int size)
{
char temp;
char *pa = (char*)ptra;
char *pb = (char*)ptrb;
for (int i = 0 ; i < size ; i++) {
temp = pa[i];
pa[i] = pb[i];
pb[i] = temp;
}
}
int main()
{
int a=1, b=5;
gswap(&a, &b, sizeof(int));
printf("%d , %d", a, b)
}
What I understand is that char has 1 byte(size) in memory and we are using pointers to swap each byte of the int value(4 bytes).
But in the end, how it is possible to dereference a char pointer to int value?
Let's try and figure this out, step by step, with code comments
#include <stdio.h>
//gswap() takes two pointers, prta and ptrb, and the size of the data they point to
void gswap(void* ptra, void* ptrb, int size)
{
// temp will be our temporary variable for exchanging the values
char temp;
// We reinterpret the pointers as char* (byte) pointers
char *pa = (char*)ptra;
char *pb = (char*)ptrb;
// We loop over each byte of the type/structure ptra/b point too, i.e. we loop over size
for (int i = 0 ; i < size ; i++) {
temp = pa[i]; //store a in temp
pa[i] = pb[i]; // replace a with b
pb[i] = temp; // replace b with temp = old(a)
}
}
int main()
{
// Two integers
int a=1, b=5;
// Swap them
gswap(&a, &b, sizeof(int));
// See they've been swapped!
printf("%d , %d", a, b);
}
So, basically, it works by going over any given datatype, reinterpreting as bytes, and swapping the bytes.

Trying to swap multiple values in a user entered array

I am trying to take a user entered array and swap the 0th value with the 7th, 8th value with the 3rd and the 0th with the 14th value. I have to use a function to swap which is where i think i messed up. When i compile it says to few arguments for function swap. also, its my 1st time using pointers so i wouldn't be surprised if there errors with that,. this is what i have, thanks!
#include <stdio.h>
void swap (int a[15], int *p, int *q, int *r ,int *s , int*t) {
int temp;
p = &a[0];
q = &a[7];
r = &a[8];
s = &a[3];
t = &a[14];
temp = *p;
*p = *q;
*q = temp;
temp = *r;
*r = *s;
*s = temp;
temp = *t;
*t = *p;
*p = temp;
}
int main (int argc, char *argv[]) {
int a[15], i;
printf(" Enter 15 integers: ");
for (i=0; i <15; i++)
swap(a);
printf(" Swapped array:\n %d", a[15]);
return 0;
}
Its not an error related to pointers.
You called swap() with one argument, like this swap(a);
And while defining it you have more then one arguments. Like
void swap (int a[15], int *p, int *q, int *r ,int *s , int*t) {
...
You do not need those extra arguments in the function definition.
Just change it to,
void swap (int a[15]) {
int temp;
int* p = &a[0];
int* q = &a[7];
int* r = &a[8];
int* s = &a[3];
int* t = &a[14];
...
A much better approach would be define a general function swap() and call it with proper required arguments multiple times when required.
void swap(int *p, int *q)
{
int tmp = *p;
*p = *q;
*q = tmp;
}
Call the above API something like
swap (&a[0], &a[7])
swap (&a[8], &a[3])
...
..

Array of pointers as function argument

How do I feed an array of pointers as an argument to a function?
In the code below, if I want my function f to take an array of pointers int *x[], how should I declare x in main() and feed it as argument to f?
void f(int *x[]){
int data[5] = {1,2,3,4,5};
int k;
for(k=0; k<5; k++){
x[k] = &(data[k]);
}
}
int main(){
int *(x[]), k, l=5;
f(x); // this does not work
for(k=0; k<l; k++){
printf("x[%d] = %d\n", k, *x[k]);
}
}
return 0;
}
Writing f(x) does not work, and neither does f(x[]) or f(x[5]).
In fact, the declaration int *(x[]) is already not recognized by my compiler, while I thought that one could declare an array of pointers without specifying the length of the array.
In main, change
int *(x[])
to
int *x[SIZE]; // SIZE is array size
Note that, you can't declare a zero size array in C except when it is a last member of a structure.
After all, your code will invoke undefined behavior because the variable data is an automatic local variable and will not exist after function returns.
You may want this:
void f(int *x[]){
int *data = malloc(5*sizeof(int);
int temp[5] = {1,2,3,4,5};
memcpy(data, temp, 5*sizeof(int));
int k;
for(k=0; k<5; k++){
x[k] = &(data[k]);
}
}
First of all your code has no sense because you are trying to fill an array of pointers that will point to local variables. That is after exiti8ng the function all pointers will be invalid because original objects will be already destroyed.
The code could have a sense if the array in the function would have static storage duration
void f(int *x[]){
static int data[5] = {1,2,3,4,5};
int k;
for(k=0; k<5; k++){
x[k] = &(data[k]);
}
}
In main array x should be defined at least as
int * x[5];
int main(){
int * x[5], k;
f(x);
for ( k=0; k < 5; k++ ){
printf("x[%d] = %d\n", k, *x[k]);
}
}
return 0;
}
An alternate way to declare an array of pointer as a parameter is to use a pointer of pointer
void f(int **x, int size){
//code
}
However, you'll have to pass the size as a second argument if you want to avoid an overflow.
To call the code you'll just have to do something like this :
int *a[] = { NULL, NULL, NULL};
f(a, 3);

Dynamic memory allocation question (in C)

Consider following codes:
#include <stdio.h>
#include <malloc.h>
void allocateMatrix(int **m, int l, int c)
{
int i;
m = (int**) malloc( sizeof(int*) * l );
for(i = 0; i < l; i++)
m[i] = (int*) malloc( sizeof(int) * c );
}
int main()
{
int **m;
int l = 10, c = 10;
allocateMatrix(m, l, c);
m[0][0] = 9;
printf("%d", m[0][0]);
return 0;
}
The code above will generate an memory allocation error and will crash.
But the code below will work correctly, the question is: WHY?
#include <stdio.h>
#include <malloc.h>
int** allocateMatrix(int l, int c)
{
int i;
int **m = (int**) malloc( sizeof(int*) * l );
for(i = 0; i < l; i++)
m[i] = (int*) malloc( sizeof(int) * c );
return m;
}
int main()
{
int **m;
int l = 10, c = 10;
m = allocateMatrix(l, c);
m[0][0] = 9;
printf("%d", m[0][0]);
return 0;
}
I cannot see why the first code crashes, since I'm just passing the pointer-to-pointer m (the variable that holds the memory first memory address of the matrix) as an argument. I see no difference between the codes (in practice). I would appreciate any clear explanation.
Thank you,
Rafael Andreatta
In the first example you don't initialize m. You merely change your copy of it. So, put otherwise, the caller will never see what you did to m.
In the second example you allocate memory and then return a pointer to it. Which is valid.
You might be able to fix your first example like this (untested but should work):
void allocateMatrix(int ***m, int l, int c)
{
int i;
*m = malloc( sizeof(int*) * l );
for(i = 0; i < l; i++)
(*m)[i] = malloc( sizeof(int) * c );
}
/* ... */
allocateMatrix(&m, l, c);
EDIT
Took me a while but I found it. As usual the C FAQ has something to say about this.
The function allocateMatrix receives a copy of the passed variable m, not the variable the you are passing from the main. Thus, in the first example m is not initialized and when you try to access is you get a segmentation fault.
This is a tricky one, and happens because with:
void allocateMatrix(int **m, int l, int c);
you're one level of indirection out. If you pass a pointer, the value that points to is in effect passed by reference. However, the actual pointer value is copied onto the stack, i.e. is still pass by value. So your allocation function has a local copy of the heap address, but this is never re-assigned to m in the preceding scope.
To fix this, you can use either the second case, or this:
void allocateMatrix(int ***m, int l, int c)
{
int i;
*m = (int**) malloc( sizeof(int*) * l );
for(i = 0; i < l; i++)
(*m)[i] = (int*) malloc( sizeof(int) * c );
}
and pass with &m.
I also would like to point out in C, you probably are better off not casting the result of malloc, although you are required to in C++. See this answer.
Because in first example variable m (in main) is not changed. To change it, you must pass it as reference (in C++) or by pointer (in plain C).

Resources