Pointers for a beginner (with code) - c

I am doing my first ever homework assignment in C and I'm trying to grasp pointers. They make sense in theory, but in execution I'm a little fuzzy. I have this code, which is supposed to take an integer x, find its least significant byte, and replace y with that byte in the same location. GCC returns with:
"2.59.c:34:2: warning: passing argument 1 of ‘replace_with_lowest_byte_in_x’ makes pointer from integer without a cast [enabled by default]
2.59.c:15:6: note: expected ‘byte_pointer’ but argument is of type ‘int’"
And the same for argument 2. Would someone be so kind as to explain to me what is going on here?
#include <stdio.h>
typedef unsigned char *byte_pointer;
void show_bytes(byte_pointer start, int length) {
int i;
for (i=0; i < length; i++) {
printf(" %.2x", start[i]);
}
printf("\n");
}
void replace_with_lowest_byte_in_x(byte_pointer x, byte_pointer y) {
int length = sizeof(int);
show_bytes(x, length);
show_bytes(y, length);
int i;
int lowest;
lowest = x[0];
for (i=0; i < length; i++) {
if (x[i] < x[lowest]) {
lowest = i;
}
}
y[lowest] = x[lowest];
show_bytes(y, length);
}
int main(void) {
replace_with_lowest_byte_in_x(12345,54321);
return 0;
}

The function expects two pointers but you're passing integer(-constant)s. What you probably want is to put the numbers in their own variables and pass the addresses of those to the function: (in main):
int a = 12345, b = 54321;
replace_with_lowest_byte_in_x(&a, &b);
Note that you're still passing incompatible pointers.

The compiler is right, your replace_with_lowest_byte_in_x() expects two unsigned char *, but you pass two ints to it. Yes, the ints can be regarded as memory address, but it's dangerous, so there is a warning. &variable gives you the address of variable.

Related

Question about the difference between Integer triple pointer and float triple pointer

I'm doing a project for school and they force us to use a type float triple pointer in a function that multiply two matrices,
and for the last day i can't figure out why when I'm using int triple pointer I get the numbers needed but when I'm using float I get zeros.
I wrote something simple just for example for the problem.
Thank you !!
int ***ptr3;
int Matrix[3][3] = { {1,2,3},{4,5,6},{7,8,9} };
int i;
ptr3 = malloc(sizeof(int));
ptr3 = Matrix;
for (i = 0; i < 9; i++) {printf_s("%d ", ptr3[i]);}
printf_s("\n");
float ***ptr3_f;
float Matrix_f[3][3] = { {1,2,3},{4,5,6},{7,8,9} };
ptr3_f = malloc(sizeof(float));
ptr3_f = Matrix_f;
for (i = 0; i < 9; i++) {printf_s("%.1f ", ptr3_f[i]);}
enter image description here
There is a whole lot of misconceptions here and your teacher does unfortunately not seem to know C very well. You simply can't use a type*** and it doesn't make any sense to use either.
A pointer of the type type*** cannot point at a 3D array of type. Nor can it point at a 2D array. It cannot point at any array type at all.
Sometimes when using dynamic memory allocation, we allocate an array of type*, each pointing at the first item in an array. A type** can then be used to point at the first type* element, to emulate the syntax of a 2D array with [i][j] access.
This does however not magically make the array of type* an array type[] at the same time. Nor does it magically make type** an array type[][]. If someone taught you that, they are confused.
Most of the time, we should not use type** to emulate a 2D array in the first place, because doing so is horribly inefficient. See Correctly allocating multi-dimensional arrays.
Thus when you attempt ptr3 = Matrix;, you get a C language constraint violation error by the compiler. Some lax compilers "only" give you a warning, but that doesn't make the code valid C. The type*** cannot be used to point at a 3D array, period.
If you somehow got the correct output in some scenario, that's by luck, since the behavior of your code isn't well-defined. On some system, int happened to have the same size as the pointer or such.
ptr3 = malloc(sizeof(int)); ptr3 = ... is senseless, since all that you achieve with the malloc is a memory leak. Because the first thing you do is to overwrite the pointer address to the data you just allocated. I'm not sure why you want to allocate a single int to begin with.
Getting rid of all misconceptions, you can perhaps salvage the program in the following manner:
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
int (*iptr)[3];
int imatrix[3][3] = { {1,2,3},{4,5,6},{7,8,9} };
iptr = imatrix;
for (int i=0; i<3; i++)
{
for (int j=0; j<3; j++)
{
printf_s("%d ", iptr[i][j]);
}
printf("\n");
}
printf("\n");
float (*fptr)[3];
float fmatrix [3][3] = { {1.0f,2.0f,3.0f},{4.0f,5.0f,6.0f},{7.0f,8.0f,9.0f} };
fptr = fmatrix;
for (int i=0; i<3; i++)
{
for (int j=0; j<3; j++)
{
printf_s("%.1f ", fptr[i][j]);
}
printf("\n");
}
}
You don't need triple pointer for such arrays.
With:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *ptr3_i;
int Matrix[3][3] = { {1,2,3},{4,5,6},{7,8,9} };
float *ptr3_f;
float Matrix_f[3][3] = { {1,2,3},{4,5,6},{7,8,9} };
int i;
ptr3_i = (int *)Matrix;
printf("ptr3_i:");
for (i = 0; i < 9; i++)
printf("%d ", ptr3_i[i]);
printf("\n");
ptr3_f = (float *)Matrix_f;
printf("ptr3_f:");
for (i = 0; i < 9; i++)
printf("%.1f ", ptr3_f[i]);
printf("\n");
return 0;
}
I get:
ptr3_i:1 2 3 4 5 6 7 8 9
ptr3_f:1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0
Did you see the warning when you compile your code:
warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]
warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘int **’ [-Wformat=]
assignment from incompatible pointer type [-Wincompatible-pointer-types]
warning: format ‘%f’ expects argument of type ‘double’, but argument 2 has type ‘float **’ [-Wformat=]
You can do something like:
ptr3 = malloc(sizeof(int**)); // allocate the memory for storing one double pointer
*ptr3 = malloc(sizeof(int*)); // allocate the memory for storing one single pointer
**ptr3 = Matrix[0]; // point to first row of the matrix
// it's similar to float pointer type
ptr3_f = malloc(sizeof(float**));
*ptr3_f = malloc(sizeof(float*));
**ptr3_f = Matrix_f[0];
Then when you want to print:
for (i = 0; i < 9; i++) {printf("%d ", (**ptr3)[i]);}
for (i = 0; i < 9; i++) {printf("%.1f ", (**ptr3_f)[i]);}

Warning: assignment makes integer from pointer without a cast in shellsort algorithm

I'm writing a program to perform shellsort on an array of numbers. I first have to generate the sequence of numbers that shellsort will be performed with. This function is to generate numbers of the form 2^p*3^q that are less than the length of the array to be sorted. Then I sort the sequence array that I just generated. Here's my implementation of this:
long * Generate_2p3q_Seq(int length, int *seq_size) {
int ind = 0;
long * arr[1000];
int product;
int power = 1;
while (power < length) {
product = power;
while (product < length) {
arr[ind] = product;
product *= 3;
ind++;
}
power *= 2;
}
int i, j, k;
for (i = 0; i < ind; ++i) {
for (j = i + 1; j < ind; ++j)
{
if (arr[i] > arr[j])
{
k = arr[i];
arr[i] = arr[j];
arr[j] = k;
}
}
}
*seq_size = ind;
for (int count = 0; count < ind; count++) {
printf("arr[%d] = %li\n", count, arr[count]);
}
return arr;
}
The code is meant to return a long * array and set seq_size to the length of the sequence array. For example, if I'm given an array of 16 integers to be sorted, the sequence array generated here should be 8 integers (1, 2, 3, 4, 6, 9, 8, 12) and seq_size should equal 8. I believe my understanding of pointers is wrong because my terminal output looks like this:
sequence.c: In function ‘Generate_2p3q_Seq’:
sequence.c:14:16: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
arr[ind] = product;
^
sequence.c:26:11: warning: assignment makes integer from pointer without a cast [-Wint-conversion]
k = arr[i];
^
sequence.c:28:16: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
arr[j] = k;
^
sequence.c:34:25: warning: format ‘%li’ expects argument of type ‘long int’, but argument 3 has type ‘long int *’ [-Wformat=]
printf("arr[%d] = %li\n", count, arr[count]);
~~^ ~~~~~~~~~~
%ln
sequence.c:36:10: warning: return from incompatible pointer type [-Wincompatible-pointer-types]
return arr;
^~~
sequence.c:36:10: warning: function returns address of local variable [-Wreturn-local-addr]
However, I'm not sure how to change this to make it work. I call this function with:
long * sequence = Generate_2p3q_Seq(size, &seq_size);
Please let me know if there's any information I've left out, I really appreciate any help.
There are two main issues here. First, you declare arr as long *arr[1000], which means it is an array of pointer to long, not an array of long. That is why you're getting about conversions between pointers and integers.
The proper way to define an array of long is:
long arr[1000];
But this then leads to the second problem, namely that you are returning a pointer to a local variable. When the function returns its local variables go out of scope, so the returned pointer no longer points to valid memory.
To fix this, declare arr as a pointer and use malloc to dynamically allocate memory for it:
long *arr = malloc((product * power) * sizeof *arr);
if (!arr) {
perror("malloc failed");
exit(1);
}
Then you can return the value of arr, which points to dynamically allocated memory.
Pass a pointer to an array as an additional parameter, and manipulate that.
void Generate_2p3q_Seq(long * arr, int length, int *seq_size) {
// Method stores result in pre-initialized arr.
}
// Call with:
long arr[1000];
Generate_2p3q_Seq(arr, length, seq_size)
// Result stored correctly in arr.

How can I generate a dynamic array in a function and reverse it in another function and return it back to screen?

I know a bit of C++ but I need to do this in C which seems to be far more complicated. As you can probably see from my code I try to have a function that generates an array and then a different function that will reverse the order of this array. The function to generate the array is just a dummy function that will be replaced by input from a different programming language (which will be done through a function that will map the values to something recognisable in C). The reverse function, even tough I know how to do it I do not know how to pass the values from my generateArray back to main and into the reverseArray (it needs to happen in this orderI cannot call reverseArray from within the generateArray).
Also, I get an error in my code right now which says:
reverse.c: In function ‘main’:
reverse.c:19:5: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
p = generateArray(m);
reverse.c: In function ‘generateArray’:
reverse.c:42:8: warning: return makes integer from pointer without a cast [-Wint-conversion]
return a;
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
//int reverseArray();
int generateArray(int size);
int main()
{
int seed = time(NULL);
int *p;
int m;
printf("please insert the size of the array:");
scanf("%d",&m);
p = generateArray(m);
for (int i=0;i<m;i++)
{
printf("%d \n", *(p+i));
}
return 0;
}
int generateArray(int size)
{
static int *a;
a = (int *)malloc(size*sizeof(int));
for(int i=0;i<size;i++)
{
a[i]=rand()%12+1;
}
return a;
}
//int reverseArray(){}

C - Copying array in other array as output argument

I am trying understand how pointers works in C. I am trying a simple case where an array, and a pointer to array are the arguments of a function which will copy the elements of the first one in the second one.
I have written this code
#include <stdio.h>
#define TAM 32
typedef int TablaArray[32];
void copyArray(TablaArray, TablaArray*, int);
void main(){
int t1[] = {1,2,3,4};
int t2[4];
copyArray(t1, t2,4);
for(int i = 0; i <= 3; i ++){
printf("%d - %d\n", t1[i], t2[i]);
}
}
void copyArray(TablaArray t1, TablaArray *t2, int tam){
for(int i = 0; i<tam-1; i++){
printf("%d\n", t1[i]);
*t2[i] = t1[i];
}
}
I am expecting to get something like this with the printf expression:
1 - 1
2 - 2
3 - 3
4 - 4
But definitely I don't know the way... I have been looking in stackoverflow and because I am sure this trivial question is already answered... but I didn't find it...
You need to make sure you are passing two int pointers pointing to both arrays. In your code only one of the arguments is a pointer. The code below should make it more clear:
#include <stdio.h>
void copyArray(int * arr1, int * arr2, int size);
int main(void)
{
int t1[] = {1,2,3,4};
int t2[4];
copyArray(t1, t2,4);
for(int i = 0; i <= 3; i ++)
{
printf("%d - %d\n", t1[i], t2[i]);
}
return 0;
}
void copyArray(int * arr1, int * arr2, int size)
{
for(int i = 0; i < size; i++)
{
printf("%d\n", arr1[i]);
arr2[i] = arr1[i];
}
return;
}
Edit: in what you have written, a TablaArray * is a pointer to an array of 32 ints, while you need an int *
typedef int TablaArray[32];
is bad practice
The problem is connected with array to pointer decay and then with pointer arithmetics:
Pointer decay means that if you pass an array-object of type int x[32] as argument to a function, then it "decays" to a pointer like int *, which points to the first element of the integer array. So be aware that if you pass an int x[32]-object, it's actually passed by reference (the array is not copied) and you may alter the contents of the array in the function.
Now pointer arithmetics:
Incrementing a pointer (or accessing an array through array subscripting) implicitly does pointer arithmetics, and the number of bytes added to the initial value depends on the type of the object to which the pointer points:
typedef int Array10[10];
Array10 arr = { 1,2,3,4,5,6,7,8,9,0 };
int *x = arr; // arrayOfInts decays to a pointer; x points to the &arr[0]
x++; // in terms of bytes, x is incremented by sizeof(int) bytes
int i = x[3]; // gets the int-value on the address of x + 3*sizeof(int)
Array10 *arr10ptr = arr;
arr10ptr++; // in terms of bytes, x is incremented by sizeof(Array10) bytes, which is 10*sizeof(int)
arr10ptr[3]; // 3*sizeof(Array10), i.e. 3*10*sizeof(int)
Now it should be clear why a function parameter being declared as a pointer to an array of int[32] behaves different from a function parameter being declared as an int[32].
So you could correct your program as follows, now knowing that TablaArray t2 will be a reference to the underlying array anyway:
void copyArray(TablaArray t1, TablaArray t2, int tam){
for(int i = 0; i<tam; i++){
printf("%d\n", t1[i]);
t2[i] = t1[i];
}
}
Hope it helps.
Compile with warnings enabled. If you used gcc -Wall -Werror, you would get the following errors:
luis.c:10:6: error: return type of ‘main’ is not ‘int’ [-Werror=main]
void main(){
^~~~
luis.c: In function ‘main’:
luis.c:15:19: error: passing argument 2 of ‘copyArray’ from incompatible pointer type [-Werror=incompatible-pointer-types]
copyArray(t1, t2,4);
^~
luis.c:8:6: note: expected ‘int (*)[32]’ but argument is of type ‘int *’
void copyArray(TablaArray, TablaArray*, int);
^~~~~~~~~
cc1: all warnings being treated as errors
The first one is simple, it should be int main.
The second one is a bit harder to see exactly because you used a typedef. So your prototype is now
void copyArray(int *, int (*)[32], int);
With the second value being a pointer-to-array that by itself is a construct that is not used often.
Instead, you'd just need two pointers to int here, and the size of an array should perhaps use size_t instead:
void copyArray(int *, int *, size_t);
void copyArray(int *t1, int *t2, size_t n){
for (int i = 0; i < tam; i++) {
t2[i] = t1[i];
}
}
Finally, if you use a C99, C11 compiler, it could be nice to use the variable-length arrays arrays to tell that one of the parameters tell the sizes of the arrays; for that we need to reorder the parameters:
void copyArray(size_t, int[*], int[*]);
void copyArray(size_t n, int t1[n], int t2[n]) {
...
}
void copyArray(TablaArray, TablaArray, int); // prototype
void copyArray(TablaArray t1, TablaArray t2, int tam){
for(int i = 0; i<tam; i++){
printf("%d\n", t1[i]);
t2[i] = t1[i];
}
}
this will help
// much faster
#include <string.h>
void copyArray(TablaArray t1, TablaArray t2, int tam){
memcpy(t2, t1, sizeof(t1[0]) * tam);
}
In Your Copy function you were copying the same value of T1 to T2 on the Address Of T2. you can do it with out pointers but pointers helps you to refer the Address

warning passing argument 1 of " " from incompatible pointer type enabled by default

randomAssign(int **grid, int size){
int m = rand()%size;
int n = rand()%size;
grid[m][n] = 1;
}
int main()
{
srand(time(NULL));
int i, j, size;
scanf("%d", &size);
int grid[size][size];
for(i=0; i<size; i++){
for(j=0; j<size; j++){
grid[i][j] = 0;
}
}
randomAssign(grid,size); //warning
return 0;
}
I am getting warning when i call the function. I tried all i can do but i couldn't find the mistake. Where is the mistake? Regards...
Arrays and pointers are different. An array is a series of contiguous elements of a particular type. A pointer is a small object that holds the address of another object.
Your function expects a pointer that points to another pointer. However you tried to supply an array to it. This can't possibly work.
One way to fix your code would be to make the function accept a pointer to an array (not a pointer to a pointer). This could be written:
void randomAssign(int size, int grid[size][size])
This is actually the same as having int (*grid)[size], the first size is redundant (see here for detail) however it serves some documentary purpose.

Resources