Invalid operands to binary - (have 'int' and 'int *') - c

I've a problem when I run the program which is:
invalid operands to binary - (have 'int' and 'int *')
Since I defined a dynamic array **engelCikacagiYer then I tried to make an operation on karakterHP
int karakterHP = 100;
int **engelCikacagiYer;
engelCikacagiYer = malloc(engelSayisi * sizeof(int));
for(i = 0; i < engelSayisi; i++){
engelCikacagiYer[i] = (rand() % (100 - 5 + 1) + 5);
}
for(i = parkurUzunlugu.Baslangic; i < parkurUzunlugu.Bitis; i++){
if (asal(engelCikacagiYer)) {
karakterHP -= engelCikacagiYer[i];
printf("%d\t", karakterHP);
}
}

This piece of code:
int **engelCikacagiYer;
engelCikacagiYer = malloc(engelSayisi*sizeof(int));
Is not correct, to allocate memory to a double pointer, aka pointer to pointer you need to allocate using the size it points to and that is pointer to int so you would need:
engelCikacagiYer = malloc(engelSayisi*sizeof(int*));
Or better yet:
engelCikacagiYer = malloc(engelSayisi*sizeof(*engelCikacagiYer));
Later you try to assign an int value to a engelCikacagiYer[i] which is a pointer variable not an int variable, hence the error.
If you really need a double pointer, after the first malloc you will need to allocate memory for each engelCikacagiYer[i] pointer:
for(int i = 0; i < engelSayisi; i++){
engelCikacagiYer[i] = malloc(sizeof(**engelCikacagiYer));
}
And assing values as if it was a 2D array (I mean using the same notation), example:
engelCikacagiYer[i][0] = (rand()%(100-5+1)+5);
or
*engelCikacagiYer[i] = (rand()%(100-5+1)+5);
Here is a simplified possible implementation of a correct allocation:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int **engelCikacagiYer;
engelCikacagiYer = malloc(100 * sizeof(*engelCikacagiYer)); //check allocation for errors
for(int i = 0; i < 100; i++){
engelCikacagiYer[i] = malloc(sizeof(**engelCikacagiYer)); //check allocation
*engelCikacagiYer[i] = (rand() % (100 - 5 + 1) + 5);
}
for (int i = 0; i < 100; i++) //test print
{
printf("%d ", *engelCikacagiYer[i]);
}
}
In any case, for the code you present using a single pointer to int would also be a valid (and simpler) solution.

Change int **engelCikacagiYer; to int *engelCikacagiYer;.
By your code it seems you want a dynamic array of ints, not a dynamic array of int pointers.

Related

C program printing garbage values

I am trying to create an array and assign values to it. While I am able to assign values correctly, I am unable to retrieve those values and I have no idea why.
Here is a part of the code snippet.
void *arr = (void *)(malloc(sizeof(void *) * 5));
int i = 0;
for(i = 0; i < 5; i++) {
*(int *)(arr+i) = initial[i];
printf("Value of array: %d\n", *(int *)(arr+i));
}
for(i = 0; i < 5; i++) {
printf("Pushing: %d\n", *(int *)(arr+i));
DArray_push(result, (arr+i));
}
The output of the program is
Value of array: 4
Value of array: 1
Value of array: 3
Value of array: 2
Value of array: 0
Pushing: 33751300
Pushing: 131841
Pushing: 515
Pushing: 2
Pushing: 0
Why is my program able to accept values correctly, but is printing out garbage values when I try to retrieve them later?
Turn warnings on. (arr+i) is not defined (you cannot add to a void pointer and you do the cast only after this addition). You see undefined behavior.
You further allocate things the size of a pointer but treat it as int (more undefined behavior).
Why not write:
int *arr = malloc(sizeof(int) * 5);
int i = 0;
for(i = 0; i < 5; i++) {
arr[i] = initial[i];
printf("Value of array: %d\n", arr[i]);
}
for(i = 0; i < 5; i++) {
printf("Pushing: %d\n", arr[i]);
}
Pushing: 33751300 = 4 + 1 * 256 + 3 * 256 * 256 + 2 * 256 * 256 * 256
Pushing: 131841 = 1 + 3 * 256 + 2 * 256 * 256
Pushing: 515 = 3 + 2 * 256
Pushing: 2
Pushing: 0
That part is already wrong, but would on most 32 or 64 bit compilers still work: sizeof(void *). Only because this this at least the size of an int on these platforms though.
*(int *)(arr+i)
This is the actual problem. This did not access the next integer, it accessed the next address addressable by a void pointer, which is typically a single byte. Accessing the next integer would had been equivalent to this:
*(int *)(arr + i*sizeof(int))
Or easier to read:
*( ((int *)arr) + i)
Remember, incrementing a pointer by an offset doesn't add to the raw memory address, but it depends on the pointer type.
The point here is the arithmetic of pointers. When we're adding a value by 1, it wouldn't be the same for different type pointers. So let's check an example:
(int *)p + 1 // it's moving 4 bytes
(void *)p + 1 // it's moving 1 byte in my compiler, void * is a generic type
In your example we know we're working with integers, so we need to tell the compiler to convert the generic pointer to the appropriate type before we do any operations with.
Try to execute the following code to understand what I'm gonna talking about:
#include <stdio.h>
#include <stdlib.h>
void main() {
int initial[] = {100, 101, 102, 103, 104};
void *arr = (void *)(malloc(sizeof(void *) * 5));
int i = 0;
for (i = 0; i < 5; i++) {
printf("%p\t%p\n", arr + i, ((int *)arr) + i);
}
for(i = 0; i < 5; i++) {
*(((int *)arr)+i) = initial[i];
printf("Value of array: %d\n", *(((int *)arr)+i));
}
for(i = 0; i < 5; i++) {
printf("Pushing: %d\n", *(((int *)arr)+i));
}
}
I found some resources to help:
https://www.cs.umd.edu/class/sum2003/cmsc311/Notes/BitOp/pointer.html
https://www.viva64.com/en/t/0005/
The thing is that you don't reset your arr pointer. Thus in your second loop you actually print the values after the initial array.
You need to create a variable to traverse your array.
void *p = arr;
And then use it to traverse the array. And again before the second loop.
Moreover, do not cast the return value of a malloc function call (even when you are casting it to a void pointer which is the actual return type of malloc).
EDIT: you actually don't change the value of arr. My bad.
First of all, the thing with casting malloc to void and using sizeof void is totally pointeless.
Assuming initial[]is another array, the fix would be:
#include <stdio.h>
#include <stdlib.h>
int initial[] = {10, 20, 30, 40, 50};
int main()
{
//allocate memory for 5 integers
int* arr = malloc(sizeof(int) * 5);
//loop over and copy from inital to arr
int i = 0;
for(i = 0; i < 5; i++) {
arr[i] = initial[i];
printf("Value of array: %d\n", arr[i]);
}
//pointer to first element of arr
int* arrPointer = arr;
for(i = 0; i < 5; i++) {
printf("Pushing: %d\n", *arrPointer);
//DArray_push(result, (*arrPointer));
//increment the arrPointer
arrPointer++;
}
//reset pointer if needed later...
arrPointer = arr;
return 0;
}

Segmentation fault when accessing a 2D array in a structure whose pointer is returned from a function

I made a structure who has two members (int and int**), and I return the pointer to this structure from one function to main(). It is fine to access the int value in the structure. However, in main() I got Segmentation fault : 11 when I tried to access the element of the 2D array.
#include<stdio.h>
#include<stdlib.h>
typedef struct Square {
int value;
int **array;
} Square;
Square * generate();
int main(int argc, char *argv[]){
Square *sqrptr = generate();
printf("%d\n", sqrptr -> value);
/* It prints 1 */
/* Print out the 2D array */
for (int i = 0; i < 3; i++){
for (int j = 0; j < 3 ; j++){
printf("%d ", *(*((sqrptr -> array) + i) + j));
}
printf("\n");
}
/* It gives segmentation fault */
return 0;
}
Square * generate(){
Square mySquare;
mySquare.value = 1;
mySquare.array = malloc(sizeof(int*) * 3);
/* Initialize the 2D array */
for (int i = 0; i < 3; i++){
*(mySquare.array + i) = malloc(sizeof(int) * 3);
for (int j = 0; j < 3; j++){
*(*(mySquare.array + i) + j) = 0;
}
}
/* Print out the 2D array */
for (int i = 0; i < 3; i++){
for (int j = 0; j < 3l ; j++){
printf("%d ", *(*(mySquare.array + i) + j));
}
printf("\n");
}
/* I can see the complete 2D array here */
Square *sqrptr = &mySquare;
return sqrptr;
}
I have tried to generate the Square in main(), and use one pointer of the structure to access my 2D array. It works fine, so I guess I have missed something when I use a pointer returned from other functions. On the other hand, I can access the int value successfully, so I have no clues now.
Could someone please explain the underlying reason for this segmentation fault? Thanks!
You're returning a pointer to a local variable (&mySquare). Stack memory (where local variables reside) is when the function returns, so the resulting pointer is pointing to invalid memory. Allocate the struct, and return the pointer to heap memory:
Square *my_square = malloc(sizeof *my_square);
//do stuff
return my_square;
Or pass a pointer to a stack variable as argument:
Square * generate(Square *my_square)
{
//in case pointer wasn't provided, allocate
if (my_square == NULL) {
my_square = malloc(sizeof *my_square);
if (!my_square)
return NULL; // or exit or whatever
}
//initialize members. To initialize array to 3x3 zero matrix, you can use:
for (int i=0;i<3;++i)
my_square.array[i] = calloc(3, sizeof *my_square->array[i]);
//or even, if you change array member to type int*:
my_square.array = calloc(3*3, sizeof *my_square->array);
//at the end:
return my_square;
}
The latter is arguably the most flexible solution: if you want to work on stack, you call the function like so:
Square my_stack_square;
generate(&my_stack_square);
If you need to use heap memory, you can use:
Square *my_heap_square = generate(NULL);
As Jonathan Leffler pointed out, for a small struct such as this, returning by value isn't too much of a cost. Getting a struct on heap can be achieved in the same way as returning any other type:
Square generate( void )
{
Square my_square;
//initialize
return my_square;
}
//call like so:
Square sq = generate();
The idea here is that you'll use a local variable in the generate function to create a new square, initialize the fields, and then return it. Because in C everything is passed by value, this essentially means the function will assign the value of the local variable from the generate function to the caller's scoped sq variable. For small structs such as this, that's perfectly fine.
What's more, a common thing for compilers to do is to optimise these kinds of functions to the equivalent of the second example I posted: Essentially your function will be creating a new Sqaure object on the stack memory of the caller. This can happen, that's not to say it will. It depends on the optimization levels used when compiling, and on the size of the struct you're returning.
Basically, if you want to keep the code as close to what you have now, it's probably easiest to stick to the first version (returning a heap pointer).
The more flexible approach is the second one (as it allows you to use stack and heap, depending on how you call the function).
For now, using the third approach is perfectly fine: the compiler will most likely optimize the code to whatever makes most sense anyway.
Try this:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef struct Square {
int value;
int **array;
} Square;
Square * generate();
int main(int argc, char *argv[]){
Square *sqrptr = generate();
printf("%d\n", sqrptr -> value);
/* It prints 1 */
/* Print out the 2D array */
int i,j;
for (i = 0; i < 3; i++){
for (j = 0; j < 3 ; j++){
printf("%d ", *(*((sqrptr -> array) + i) + j));
}
printf("\n");
}
/* It gives segmentation fault */
return 0;
}
Square * generate(){
Square* mySquare = (Square*) malloc(sizeof(Square)); //c++ compiler
//Square* mySquare = (void*) malloc(sizeof(Square)); //c compiler
mySquare->value = 1;
mySquare->array = malloc(sizeof(int*) * 3);
/* Initialize the 2D array */
int i,j;
for (i = 0; i < 3; i++){
*(mySquare->array + i) = malloc(sizeof(int) * 3);
for (j = 0; j < 3; j++){
*(*(mySquare->array + i) + j) = 0;
}
}
/* Print out the 2D array */
for (i = 0; i < 3; i++){
for (j = 0; j < 3l ; j++){
printf("%d ", *(*(mySquare->array + i) + j));
}
printf("\n");
}
/* I can see the complete 2D array here */
return mySquare;
}

changing adress of pointer created using malloc

I am trying to understand how malloc and pointer works.
#include <stdio.h>
#include <stdlib.h>
int main() {
int *p;
int b = 15;
p = (int *)malloc(sizeof(int) * 10);
for (int i = 0; i < 5; i++) {
p + i = &b;
}
}
The above code gives error
expression is not assignable
p + i = &b;
As far as I understand, malloc gives the starting address of the memory allocated in heap which I typecast to hold the address of integers. So technically, p + i should be able to hold any integer address, but the code throws an error. Can you please explain why this is wrong.
Thanks
The line of code p = (int *)malloc(sizeof(int) * 10); means that the pointer p is assigned the address of the first element of the dynamically allocated array with malloc(),which has allocated an int array consisting of 10 elements.
If you want to assign 5 of these elements the value of b then you write:
for (int i = 0; i < 5; i++) {
p[i] = b;
}
If however you want an array of 10 integer pointers and want to assign 5 of them the address of b,then you write:
int **pointer = (int **)malloc(sizeof(int *) * 10);
for (int i = 0; i < 5; i++) {
pointer[i] = &b;
}
Don't forget to free dynamically allocated memory when you finish.
p + i is pointing to an address on your memory, the same as &(p[i]). You can't change the address of the memory, so that's why the compiler is saying the expression is not assignable.
If you want to save an int on that address you need to use *(p+i) = b.
But if you want to save the address of an int you need an array which holds int*, so you need to declare p as an int** and allocate its memory with the sizeof(int*). That way your code would look like this:
#include <stdio.h>
#include <stdlib.h>
int main() {
int **p;
int b = 15;
p = (int**)malloc(sizeof(int*) * 10);
for (int i = 0; i < 5; i++) {
*(p + i) = &b;
}
}

C: adding elements to an array

I'm trying to test a program that creates an array with 0 elements in it, then adds elements to it (reallocating memory each time), and then printing out the elements. But, I keep getting errors when I try to run it.
int main(int argc, const char * argv[]) {
int num = 0;
int n = 10;
int **array = malloc(0);
for (int i = 0; i < n; ++i)
{
++num;
array = realloc(array, num * sizeof(int*));
array[num-1] = &i;
}
for (int j = 0; j < n; ++j)
{
printf("%d", &array[j]); // error 1
}
return 0;
}
I'm sorry I didn't include the errors with the original post. I think I fixed one of them. Here is the other:
Error 1: Format specifies type 'int' but the argument has type 'int *'
This answer is based on the assumption that you are printing a simple array, since you don't show what output you expect. You are using one more step of indirection than you need, and too many variables. Take note that indexing is different from length (often by 1).
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int i, n = 10;
int *array = NULL; // no need for double star, or fake allocation
for (i = 0; i < n; ++i)
{
array = realloc(array, (i + 1) * sizeof(int)); // remove the *, add 1 for num elements
array[i] = i;
}
for (i = 0; i < n; ++i)
{
printf("%d", array[i]); // remove the &
}
free(array); // don't forget this
return 0;
}
Program output:
0123456789
In practice, you should assign the result of realloc to another pointer variable, check it's ok, and then replace the original pointer var.
printf("%d", &array[j]); // error 1
The & is the address operator. So it is making something a pointer. Your array is already an array of pointers to integer.
By using the & you are trying to print the address of the integer pointer itself.
Try using * instead of &. * means that you want to print the value of the integer pointer.
printf("%d", *array[j]); // error 1

How to return an array from a function with pointers

i'm trying to figure out how to return an array from a function in the main().
I'm using C language.
Here is my code.
#include <stdio.h>
int *initArray(int n){
int i;
int *array[n];
for(i = 0; i < n; i++){
array[i] = i*2;
}
return array;
}
main(){
int i, n = 5;
int *array[n];
array[n] = initArray(n);
printf("Here is the array: ");
for(i = 0; i < n; i++){
printf("%d ", array[i]);
}
printf("\n\n");
}
And this is the errors the console gives me:
2.c: In function ‘initArray’:
2.c:8:13: warning: assignment makes pointer from integer without a cast [enabled by default]
array[i] = i*2;
^
2.c:11:3: warning: return from incompatible pointer type [enabled by default]
return array;
^
2.c:11:3: warning: function returns address of local variable [-Wreturn-local-addr]
2.c: In function ‘main’:
2.c:23:4: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘int *’ [-Wformat=]
printf("%d ", array[i]);
^
It's impossible!
I hate being a noob :(
If you could help, with explanations, I would appreciate! :D
Edit: iharob's answer is better than mine. Check his answer first.
Edit #2: I'm going to try to explain why your code is wrong
Consider the 2nd line of main() in your question:
int *array[n];
Let's try to read it backwards.
[n]
says we have an array that contains n elements. We don't know what type those elements are and what the name of the array is, but we know we have an array of size n.
array[n]
says your array is called array.
* array[n]
says you have a pointer to an array. The array that is being pointed to is called 'array' and has a size of n.
int * array[n];
says you have a pointer to an integer array called 'array' of size n.
At this point, you're 3/4 way to making a 2d array, since 2d arrays consist of a list of pointers to arrays. You don't want that.
Instead, what you need is:
int * array;
At this point, we need to examine your function, initArray:
int *initArray(int n){
int i;
int *array[n];
for(i = 0; i < n; i++){
array[i] = i*2;
}
return array;
}
The second line of initArray has the same mistake as the second line of main. Make it
int * array;
Now, here comes the part that's harder to explain.
int * array;
doesn't allocate space for an array. At this point, it's a humble pointer. So, how do we allocate space for an array? We use malloc()
int * array = malloc(sizeof(int));
allocates space for only one integer value. At this point, it's more a variable than an array:
[0]
int * array = malloc(sizeof(int) * n);
allocates space for n integer variables, making it an array:
e.g. n = 5:
[0][0][0][0][0]
Note:The values in the real array are probably garbage values, because malloc doesn't zero out the memory, unlike calloc. The 0s are there for simplicity.
However, malloc doesnt always work, which is why you need to check it's return value:
(malloc will make array = NULL if it isn't successful)
if (array == NULL)
return NULL;
You then need to check the value of initArray.
#include <stdio.h>
#include <stdlib.h>
int *initArray(int n){
int i;
int *array = malloc(sizeof(int) * n);
if (array == NULL)
return NULL;
for(i = 0; i < n; i++){
array[i] = i*2;
}
return array;
}
int main(){
int i, n = 5;
int *array = initArray(n);
if (array == NULL)
return 1;
printf("Here is the array: ");
for(i = 0; i < n; i++){
printf("%d ", array[i]);
}
free(array);
printf("\n\n");
return 0;
}
You can't just return an array like that. You need to make a dynamically allocated array in order to do that. Also, why did you use a 2d array anyway?
int array[5];
is basically (not completely) the same as:
int * array = malloc(sizeof(int) * 5);
The latter is a bit more flexible in that you can resize the memory that was allocated with malloc and you can return pointers from functions, like what the code I posted does.
Beware, though, because dynamic memory allocation is something you don't wanna get into if you're not ready for tons of pain and debugging :)
Also, free() anything that has been malloc'd after you're done using it and you should always check the return value for malloc() before using a pointer that has been allocated with it.
Thanks to iharob for reminding me to include this in the answer
Do you want to initialize the array? You can try it like this.
#include <stdio.h>
void initArray(int *p,int n)
{
int i;
for(i = 0; i < n; i++)
{
*(p+i) = i*2;
}
}
void main(void)
{
int i, n = 5;
int array[n];
initArray(array,n);
printf("Here is the array: ");
for(i = 0; i < n; i++)
{
printf("%d ", array[i]);
}
printf("\n\n");
}
If you don't want to get in trouble learning malloc and dynamic memory allocation you can try this
#include <stdio.h>
void initArray(int n, int array[n]) {
int i;
for (i = 0 ; i < n ; i++) {
array[i] = i * 2;
}
}
int main() { /* main should return int */
int i, n = 5;
int array[n];
initArray(n, array);
printf("Here is the array: ");
for(i = 0 ; i < n ; i++) {
printf("%d ", array[i]);
}
printf("\n\n");
return 0;
}
as you see, you don't need to return the array, if you declare it in main(), and pass it to the function you can just modify the values directly in the function.
If you want to use pointers, then
#include <stdio.h>
int *initArray(int n) {
int i;
int *array;
array = malloc(n * sizeof(*array));
if (array == NULL) /* you should always check malloc success */
return NULL;
for (i = 0 ; i < n ; i++) {
array[i] = i * 2;
}
return array;
}
int main() { /* main should return int */
int i, n = 5;
int *array;
array = initArray(n);
if (array == NULL) /* if null is returned, you can't dereference the pointer */
return -1;
printf("Here is the array: ");
for(i = 0 ; i < n ; i++) {
printf("%d ", array[i]);
}
free(array); /* you sould free the malloced pointer or you will have a memory leak */
printf("\n\n");
return 0;
}

Resources