Why can uninitialized pointer to int array be assigned variable's value? - c

I have read answers to questions like why a pointer can be assigned value? however I'm still a bit confused about changing the values of pointers. Some of the comments don't seem to be completely accurate, or maybe it's implementation specific. (example: a[1] is exactly the same as writing *(a + 1). Obviously you can write *a = 3 since a is int*, so you can also write *(a + 1) = 3, so you can also write a[1] = 3).
Writing *a = 3 produces a warning: initialization makes pointer from integer without a cast. As well as a segfault.
My question is as follows.
int main(void)
{
int b = 5, c = 10;
int *a = b;
*a = c; /* Will not work. (Should technically change the value of b to 10, leaving the pointer still pointing to b.) */
printf("%d\n", *a);
return 0;
}
The above example will not work, and will produce a segfault, but the following works for some reason I am not aware of.
int main(void)
{
int a[10], i;
for (i = 0; i < 10; ++i) {
*(a + i) = i; /* Supposedly the same logic as '*a = c;', but works*/
}
for (i = 0; i < 10; ++i) {
printf("%d\n", *(a + i));
}
return 0;
}
Thanks for your time and efforts.
**EDIT: Thank you for the answers, since it is *a = &b (I knew this (typo), but now the second example with the loop is unclear), the array indices are treated as variables, not as addresses I presume?

This:
int b = 5, c = 10;
int *a = b;
Doesn't work. You think the second line means this:
int *a;
*a = b;
But it doesn't. It means this:
int *a;
a = b;
The above error means that when you do this:
*a = c;
Your program crashes (or maybe not, undefined behavior!), because a is an invalid pointer (it points to address 5, which is wrong in many ways).

Related

Pointer arithmetic in C not pointing to the correct variables if I don't print the address of the variables

So I'm doing pointer arithmetic homework and I need to decrement and increment pointers with this as its expected outcome. This is what I did
#include <stdio.h>
void main(void){
int d = 10;
int c = 8;
int b = 6;
int a = 4;
int *ptr; //these lines are given
printf("decrement \n");
for (ptr = &d; ptr >= &a; ptr--)
{
printf("%d \n",*ptr);
}
printf("increment \n");
for (ptr = &a; ptr <= &d; ptr++)
{
printf("%d \n",*ptr);
}
}
But the results skip 8 and 6:
decrement
10
4
increment
4
10
And so I decided to print the addresses at the beginning to help debug
printf("%p\n",(void*)&d);
printf("%p\n",(void*)&c);
printf("%p\n",(void*)&a);
printf("%p\n",(void*)&b);
But after running it, it just works
000000fc6a9ffb34
000000fc6a9ffb30
000000fc6a9ffb28
000000fc6a9ffb2c
decrement
10
8
6
4
increment
4
6
8
10
So I know that the logic works out, but it just doesn't work without printing first and I don't know why
I'm using Vscode and GCC
So I know that the logic works out, but it just doesn't work without printing first
Undefined behavior (UB), anything may happen.
int d = 10;
int a = 4;
int *ptr = &d;
ptr >= &a
ptr >= &a is undefined behavior (UB).
Order comparisons of pointers in C are UB when not part of the same array (or one after).
ptr-- is also UB as that attmepts to form the address before d. Pointer math only good within an array/object (or one after)
In your first example, you are not using variables b and c, just a and d - therefore (I suspect) the implementation is optimizing them away
In the second example, you are using variables all four variables a, b, c and d therefore they cannot be optimised away
your program have four different variables not an array of size four. So address of variables is unpredictable.
int d = 10;
int c = 8;
int b = 6;
int a = 4;
in Array memory is allocated contiguously, so use array if you want to do so.
#include<stdio.h>
int main(){
int arr[4] = {1, 2, 3, 4};
// increment
for(int i=0; i<4; i++)
printf("%d\n",*(arr + i));
// decrement
printf("-------------------------------\n");
for(int i=3; i>=0; i--)
printf("%d\n",*(arr + i));
return 0;
}

Assigning int* from incompatible void *

I have this code:
int * generate_code(int *bits, int Fs, int size, int *signal_size, float frameRate)
{
int sign_prev, i;
int bit, t, j=0;
int *x;
float F0, N, t0, prev_i, F1;
int temp = 0, temp1, temp2;
F0 = frameRate * BITS_PER_FRAME; // Frequency of a train of '0's = 2.4kHz
F1 = 2*F0; // Frequency of a train of '1's = 4.8kHz
N = 2*(float)Fs/F1; // number of samples in one bit
sign_prev = -1;
prev_i = 0;
x = (int *)malloc(sizeof(int));
for( i = 0 ; i < size ; i++)
{
t0 = (i + 1)*N;
bit = bits[i];
if( bit == 1 )
{
temp1 = (int)round(t0-N/2)-(int)round(prev_i+1)+1;
temp2 = (int)round(t0)-(int)round(t0-N/2+1)+1;
temp =j + temp1 + temp2;
//printf("%d\n", (int)temp);
x = realloc(x, sizeof(int)*temp); // 1
for(t=(int)round(prev_i+1); t<=(int)round(t0-N/2); t++)
{
*(x + j) = -sign_prev;
j++;
}
prev_i = t0-N/2;
for(t=(int)round(prev_i+1); t <= (int)round(t0); t++)
{
*(x + j) = sign_prev;
j++;
}
}
else
{
// '0' has single transition and changes sign
temp =j + (int)round(t0)-(int)round(prev_i);
//printf("%d\n",(int)temp);
x = realloc(x, sizeof(int)*(int)temp); // 2
for(t=(int)round(prev_i); t < (int)round(t0); t++)
{
*(x + j) = -sign_prev;
j++;
}
sign_prev = -sign_prev;
}
prev_i = t0;
}
*signal_size = j;
return x;
}
Both realloc lines, marked with //1 and //2 on the previous code, give me this error message:
assigning to int * from incompatible type void *
Because I don't want this code behaving weirdly or crashing on me, obviously, I ask will: I have some problem in the future if I simply cast it to int * by doing
x = (int*)realloc(x, sizeof(int)*(int)temp);
Thanks
In C, a value of type void* (such as the value returned by realloc) may be assigned to a variable of type int*, or any other object pointer type. The value is implicitly converted.
The most likely explanation for the error message is that you're compiling the code as C++ rather than as C. Make sure the source file name ends in .c, not .C or .cpp, and make sure your compiler is configured to compile as C rather than as C++.
(Casting the result of realloc or malloc is considered poor style in C. In C++, the cast is necessary, but you normally wouldn't use realloc or malloc in C++ in the first place.)
This should work in C. Are you perhaps using a C++ compiler to compile this? For example, some big company based in Redmond refuses to properly support a contemporary C implementation. Their compiler is C++ by default and needs some option to whack it into a C compiler.
You have stdlib.h included? Then you don't need the casts. In fact, it is best practice to not cast the malloc return.
All alloc-style functions in C return memory addresses with the most strict alignment, so the cast can't give a pointer that isn't a valid int pointer.

pointer arithmetic with pointer to array

I'm trying to do pointer arithmetic with a pointer to array, but I get a wrong value since I can't dereference the pointer properly.
Here is the code:
#include "stdlib.h"
#include "stdio.h"
int main()
{
int a[] = {10, 12, 34};
for (int i = 0; i < 3; ++i)
{
printf("%d", a[i]);
}
printf("\n");
int (*b)[3] = &a;
for (int i = 0; i < 3; ++i)
{
printf("%d", *(b++));
}
printf("\n");
return 0;
}
In the second for I can't get to print the correct value.
It doesn't work even if I write
printf("%d", *b[i]);
I'd like to see how to print correctly using the b++ and the b[i] syntax.
The following should work:
printf("%d\n", *( *b+i ));
// * b + i will give you each consecutive address starting at address of the first element a[0].
// The outer '*' will give you the value at that location.
instead of:
printf("%d", *(b++));
You have declared b to be a pointer to arrays of 3 integers and you have initialized it with address of a.
int (*b)[3] = &a;
In the first loop you will print the first element of a array but then you will move 3*sizeof(int) and trigger undefined behavior trying to print whatever there is.
To print it correctly:
int *b = a;
// int *b = &a[0]; // same thing
// int *b = (int*)&a; // same thing, &a[0] and &a both points to same address,
// though they are of different types: int* and int(*)[3]
// ...so incrementing they directly would be incorrect,
// but we take addresses as int*
for (int i = 0; i < 3; ++i)
{
printf("%d", (*b++));
}
gcc will complain about the formatting in the second for loop: it will tell you format specifies type 'int' but the argument has type 'int *
your assignment of a to b should look like this:
int *b = a

Why am I getting segmentation fault for malloc() while using pointer to pointer?

I don't understand why this works:
void main() {
int * b;
b = (int *)malloc(sizeof(int));
*b = 1;
printf("*b = %d\n", *b);
}
while this does not (gets segmentation fault for the malloc()):
void main() {
int ** a;
int i;
for (i = 0; i<= 3; i++) {
a[i] = (int*)malloc(sizeof(int));
*(a[i]) = i;
printf("*a[%d] = %d\n", i, *(a[i]));
}
}
since I find a[i] is just like b in the first example.
BTW, a[i] is equal to *(a+i), right?
You need to allocate memory for a first, so that you can access its members as a[i].
So if you want to allocate for 4 int * do
a = malloc(sizeof(int *) * 4);
for (i = 0; i<= 3; i++) {
...
}
or define it as array of integer pointers as
int *a[4];
a is a 2 dimensional pointer, you have to allocate both dimension.
b is a 1 dimensional pointer, you have to allocate only one dimension and that's what you're doing with
b = (int *)malloc(sizeof(int));
So in order the second example to work you have to allocate the space for the pointer of pointer
void main() {
int ** a;
int i;
a = (int**)malloc(4*sizeof(int*));
for (i = 0; i<= 3; i++) {
a[i] = (int*)malloc(sizeof(int));
*(a[i]) = i;
printf("*a[%d] = %d\n", i, *(a[i]));
}
The allocated pointer is written to uninitialized memory (you never set a to anything), causing undefined behavior.
So no, it's not at all equivalent to the code in the first example.
You would need something like:
int **a;
a = malloc(3 * sizeof *a);
first, to make sure a holds something valid, then you can use indexing and assign to a[0].
Further, this:
a[i] = (int*)malloc(sizeof(int));
doesn't make any sense. It's assigning to a[i], an object of type int *, but allocating space for sizeof (int).
Finally, don't cast the return value of malloc() in C.
actually malloc it's not that trivial if you really want safe and portable, on linux for example malloc could return a positive response for a given request even if the actual memory it's not even really reserved for your program or the memory it's not writable.
For what I know both of your examples can potentially return a seg-fault or simply crash.
#ruppells-vulture I would argue that malloc is really portable and "safe" for this reasons.

Incrementing variables using pointers

I'm very new to dealing with pointers, and my C knowledge is fairly small. I'm trying to understand pointers. I wrote the following code to print a list of variables (a to f) like so:
0
1
2
3
4
5
I wrote the following code to do this:
#include <stdio.h>
int main(){
int a,b,c,d,e,f;
int *p;
int i;
a = b = c = d = f = 0;
p = &a;
for (i = 0; i < 5; i++){
*p += i;
printf("%d\n", *p);
p++;
}
return 0;
}
The idea was it works through the variables and increments each by an ever-increasing number (i). I am assuming that as you initialize the variables at the same time, they'd be placed next to each other in memory. However, I get the following output:
0
1
2
3
-1218283607
If I change the for loop to only go from 0 to 3 (i < 4), it works fine, printer 0 1 2 and 3. But when I wish to print the variable f as well, it doesn't seem to set it.
As I said, I'm very new to pointers so I've probably overlooked something silly, but I've been looking through my code over and over, trying to work it out.
Thanks in advance.
There is no guarantee that a, b, c, d, e and f will be adjacent in memory. If you want that sort of guarantee you need to use an array.
#include <stdio.h>
int main() {
int a[6];
int *p;
int i;
a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = 0;
p = &a[0];
for (i = 0; i < 6; i++){
*p += i;
p++;
}
for(i = 0; i < 6; i++) {
printf("%d\n", a[i]);
}
return 0;
}
Here int a[6] is declaring an array named a that can hold six integers. These six integers can obtained via a[0], a[1], a[2], a[3], a[4] and a[5]. You are guaranteed that a[0], a[1], a[2], a[3], a[4] and a[5] are layed out contiguously in memory. Thus the line
p = &a[0];
sets p to the address of the first element. Each increment of this pointer moves us forward one position in the array.
The second for loop shows that first for loops correctly sets a[i] to i for i in {0, 1, 2, 3, 4, 5}. If you run this program you will see
0
1
2
3
4
5
on the console.
You forgot to initialize e. But yes, use a packed array.
It isn't safe to assume that stack variables are arranged in memory in any particular order.
You need to use an array, a struct or possibly a union to gurantee the ordering of your ints.
union {
int ary[6];
struct {
int a;
int b;
int c;
int d;
int e;
int f;
} s;
} u = {0};
p = &u.s.a;
for (i = 0; i < 5; i++){
*p += i;
printf("%d\n", *p);
p++;
}

Resources