How should I write an array that should be saved in heap? - c

I wrote this till now:
int *p;
p = (int*)malloc(sizeof(int[]));
did I wrong?
I was expecting write a size of the array but without that the programme functions, right?

int *p;
p = (int*)malloc(sizeof(int[]));
did I wrong?
The code is not valid C. int[] is the type name of an incomplete type, and as such, it is not a valid operand of the sizeof operator. This violates a language constraint, so a conforming C implementation is required to emit a diagnostic when it processes the code presented.
I was expecting write a size of the array but without that the
programme functions, right?
If you are saying that a program containing the code presented compiles and runs successfully then that is surprising, but ultimately it means nothing. The program has undefined behavior as far as the C language specification is concerned, but that does not mean that a compiler must reject it (after emitting the required diagnostic), or that it must fail at runtime. Other than the diagnostic, the spec doesn't say anything about what will happen -- that's what "undefined behavior" means.

Related

difference between static const int vs const int

const int a = 100;
int *p = &a;
*p = 99;
printf("value %d", a);
Above code compiles and I am able to update its value via pointer but code below didn't output anything.
static const int a = 100;
int *p = &a;
*p = 99;
printf("value %d", a);
Can anyone explain this thing.
Both code snippets are invalid C. During initialization/assignment, there's a requirement that "the type pointed to by the left has all the qualifiers of the type pointed to
by the right" (c17 6.5.16.1). This means we can't assign a const int* to an int*.
"Above code compiles" Well, it doesn't - it does not compile cleanly. See What must a C compiler do when it finds an error?.
I would recommend you to block invalid C from compiling without errors by using (on gcc, clang, icc) -std=c11 -pedantic-errors.
Since the code is invalid C, it's undefined behavior and why it has a certain behavior is anyone's guess. Speculating about why you get one particular output from one case of undefined behavior to another isn't very meaningful. What is undefined behavior and how does it work? Instead focus on writing valid C code without bugs.
There are several things going on here:
const does not mean "Put this variable in read-only memory or otherwise guarantee that any attempt to modify it will definitively result in an error message."
What const does mean is "I promise not to try to modify this variable." (But you broke that promise in both code fragments.)
Attempting to modify a const-qualified variable (i.e., breaking your promise) yields undefined behavior, which means that anything can happen, meaning that it might do what you want, or it might give you an error, or it might do what you don't want, or it might do something totally different.
Compilers don't always complain about const violations. (Though a good compiler should really have complained about the ones here.)
Some compilers are selective in their complaints. Sometimes you have to ask the compiler to warn about iffy things you've done.
Some programmers are careless about ignoring warnings. Did your compiler give you any warnings when you compiled this?
The compiler should complain in both cases when you store the address of a const int into p, a pointer to modifiable int.
In the first snippet, a is defined as a local variable with automatic storage: although you define it as const, the processor does not prevent storing a value into it via a pointer. The behavior is undefined, but consistent with your expectations (a is assigned the value 99 and this value is printed, but the compiler could have assumed that the value of a cannot be changed, hence could have passed 100 directly to printf without reading the value of a).
In the second snippet, a is a global variable only accessible from within the current scope, but the compiler can place it in a read-only location, causing undefined behavior when you attempt to modify its value via the pointer. The program may terminate before evaluating the printf() statement. This is consistent with your observations.
Briefly, modifying const-qualified static objects causes a trap and modifying a const-qualified automatic object does not because programs are able to place static objects in protected memory but automatic objects must be kept in writeable memory.
In common C implementations, a const-qualified static object is placed in a section of the program data that is marked read-only after it is loaded into memory. Attempting to modify this memory causes the processor to execute a trap, which results in the operating system terminating execution of the program.
In contrast, an object with automatic storage duration (one defined inside a function without static or other storage duration) cannot easily be put in a read-only program section. This is because automatic objects need to be allocated, initialized, and released during program execution, as the functions they are defined in are called and returned. So even though the object may be defined as const for the purposes of the C code, the program needs to be able to modify the memory actually used for it.
To achieve this, common C implementations put automatic objects on the hardware stack, and no attempt is made to mark the memory read-only. Then, if the program mistakenly attempts to modify a const-qualified automatic object, the hardware does not prevent it.
The C standard requires that the compiler issue a diagnostic message for the statement int *p = &a;, since it attempts to initialize a pointer to non-const with the address of a const-qualified type. When you ignore that message and execute the program anyway, the behavior is not defined by the C standard.
Also see this answer for explanation of why the program may behave as though a is not changed even after *p = 99; executes without trapping.
6.7.3 Type qualifiers
...
6 If an attempt is made to modify an object defined with a const-qualified type through use
of an lvalue with non-const-qualified type, the behavior is undefined. If an attempt is
made to refer to an object defined with a volatile-qualified type through use of an lvalue
with non-volatile-qualified type, the behavior is undefined.133)
133) This applies to those objects that behave as if they were defined with qualified types, even if they are
never actually defined as objects in the program (such as an object at a memory-mapped input/output
address).
C 2011 Online Draft
If you declare a as const, you're making a promise to the compiler that the value of a should not change during its lifetime; if you try to assign a new value to a directly the compiler should at least issue a diagnostic. However, by trying to change a through a non-const pointer p you're breaking that promise, but you're doing it in such a way that the compiler can't necessarily detect it.
The resulting behavior is undefined - neither the compiler nor the runtime environment are required to handle the situation in any particular way. The code may work as expected, it may crash outright, it may appear to do nothing, it may corrupt other data. const-ness may be handled in different ways depending on the compiler, the platform, and the code.
The use of static changes how a is stored, and the interaction of static and const is likely what's leading to the different behavior. The static version of a is likely being stored in a different memory segment which may be read-only.

Assigning a "string" to a varible previously declared as "int"

I am new to programming and on learning dynamic typing in python, it arisess a doubt in "static typing". I tried out this code (assigning a string to an integer variable which was previously declared) and printing the variable as printf(var_name) and its gives output; can anyone explain this concept?
#include<stdio.h>
#include<conio.h>
void main()
{
int i = 20 ;
i = "hello";
printf(i);
}
Besides your question might be a duplicate, let me append something missing of the read worthy answer https://stackoverflow.com/a/430414/3537677
C is strongly/statically typed but weakly checked
This is one of the biggest core language features which sets C apart from other languages like C++. (Which people are used to mistake a simply "C with classes"
Meaning although C has a strong type system in the context of needing and using it for knowing sizes of types at compile time, the C languages does not have a type system in order to check them for misuse. So compilers are neither mandated to check it nor are they allowed to error your code, because its legal C code. Modern compilers will issue a warning dough.
C compilers are only ensuring "their type system" for the mentioned size management. Meaning, if you just type int i = 42; this variable has so called automatic storage duration or what many people are calling more or less correctly "the stack". It means the compiler will take care of getting space for the variable and cleaning it up. If it can not know the size of it, but needs it then it will indeed generate an error. But this can be circumvented by doing things at run-time and using of types without any type whats so ever, i.e. pointers and void* aka void-pointers.
Regarding your code
Your code seems to be an old, non standard C compiler judging by the #include<conio.h> and void returning main. With a few modifications one can compile your code, but by calling printf with an illegal format string, you are causing so called undefined behaviour (UB), meaning it might work on your machine, but crashes on mine.

Using return 0 with void main()?

I was just trying to see what would happen, if I use return 0 statement with void main(). I was expecting that the compiler would give an error but it just gave a warning and successfully executed the program but at last, returned some non zero value, now I have doubt why the program executes without an error and then also return some value when I have used void main()?
#include<stdio.h>
void main()
{
printf("Hello World\n");
return 0;
}
Using return 0; in a function that returns void is a constraint violation:
6.8.6.4 The return statement
Constraints
1 A return statement with an expression shall not appear in a function whose return type
is void. A return statement without an expression shall only appear in a function
whose return type is void.
C 2011 online draft
The compiler must issue a diagnostic for a constraint violation (the warning you saw during compilation) - however, the compiler may continue to translate the program and generate an executable (the difference between a warning and an error, and whether it halts translation, is up to the implementation).
Secondly, unless your compiler's documentation explicitly lists void as a valid return type for main, using void main results in undefined behavior - at that point, the compiler is not required to handle the situation in any particular way.
Usually, trying to figure out how you got a specific result from undefined behavior is a waste of time, since the behavior may not be repeatable. In this case, you told the compiler main wasn't going to return a value and it generated the machine code accordingly. It's likely that the register used for that return value was overwritten as soon as main returned.
i have doubt why the program executes without a error and then also return some value when i have used void main()
The C standard says that the right thing to do is int main, and that a conforming implementation is permitted to allow other signatures on main if it so chooses.
Apparently your implementation chooses to allow this non-standard usage, and that the behaviour it exhibits is a warning at compile time followed by the observed behaviour at runtime.
But you already knew that. The compiler does what the compiler does because the compiler authors wrote it that way. If you want to know why they made those choices, ask them. Since you have not said what compiler you are using, we have nothing more to go on.
Your code is not a valid C code. C language does not allow you to use return 0 in a void function. It is a constraint violation, i.e. what we colloquially call an error. Every conforming C compiler is required to issue a diagnostic message for this code, after which the behavior of your code is undefined from the point of view of standard C language.
According to your description, your compiler did issue a diagnostic message for this code, as required by the language specification. After that, whatever behavior you observed from the compiled code might (or might not be) defined by your specific compiler, but it is no longer defined by the language itself.
This return value of main is typically utilized the operating system where the program runs to determine if there was an error during execution or not, typically the value 0 is success and other values are interpreted as an error by convention.

Why does the following code give different results when compiling with gcc and g++?

#include<stdio.h>
int main()
{
const int a=1;
int *p=(int *)&a;
(*p)++;
printf("%d %d\n",*p,a);
if(a==1)
printf("No\n");//"No" in g++.
else
printf("Yes\n");//"Yes" in gcc.
return 0;
}
The above code gives No as output in g++ compilation and Yes in gcc compilation. Can anybody please explain the reason behind this?
Your code triggers undefined behaviour because you are modifying a const object (a). It doesn't have to produce any particular result, not even on the same platform, with the same compiler.
Although the exact mechanism for this behaviour isn't specified, you may be able to figure out what is happening in your particular case by examining the assembly produced by the code (you can see that by using the -S flag.) Note that compilers are allowed to make aggressive optimizations by assuming code with well defined behaviour. For instance, a could simply be replaced by 1 wherever it is used.
From the C++ Standard (1.9 Program execution)
4 Certain other operations are described in this International
Standard as undefined (for example, the effect of attempting to
modify a const object). [ Note: This International Standard imposes
no requirements on the behavior of programs that contain undefined
behavior. —end note ]
Thus your program has undefined behaviour.
In your code, notice following two lines
const int a=1; // a is of type constant int
int *p=(int *)&a; // p is of type int *
you are putting the address of a const int variable to an int * and then trying to modify the value, which should have been treated as const. This is not allowed and invokes undefined behaviour.
For your reference, as mentioned in chapter 6.7.3, C11 standard, paragraph 6
If an attempt is made to modify an object defined with a const-qualified type through use
of an lvalue with non-const-qualified type, the behavior is undefined. If an attempt is
made to refer to an object defined with a volatile-qualified type through use of an lvalue
with non-volatile-qualified type, the behavior is undefined
So, to cut the long story short, you cannot rely on the outputs for comaprison. They are the result of undefined behaviour.
Okay we have here 'identical' code passed to "the same" compiler but once
with a C flag and the other time with a C++ flag. As far as any reasonable
user is concerned nothing has changed. The code should be interpreted
identically by the compiler because nothing significant has happened.
Actually, that's not true. While I would be hard pressed to point to it in
a standard but the precise interpretation of 'const' has slight differences
between C and C++. In C it's very much an add-on, the 'const' flag
says that this normal variable 'a' should not be written to by the code
round here. But there is a possibility that it will be written to
elsewhere. With C++ the emphasis is much more to the immutable constant
concept and the compiler knows that this constant is more akin to an
'enum' that a normal variable.
So I expect this slight difference means that slightly different parse
trees are generated which eventually leads to different assembler.
This sort of thing is actually fairly common, code that's in the C/C++
subset does not always compile to exactly the same assembler even with
'the same' compiler. It tends to be caused by other language features
meaning that there are some things you can't prove about the code right
now in one of the languages but it's okay in the other.
Usually C is the performance winner (as was re-discovered by the Linux
kernel devs) because it's a simpler language but in this example, C++
would probably turn out faster (unless the C dev switches to a macro
or enum
and catches the unreasonable act of taking the address of an immutable constant).

Why is it allowed to overwrite a const variable using a pointer to it using memcpy?

Why is it allowed to change a const variable using a pointer to it with memcpy?
This code:
const int i=5;
int j = 0;
memcpy(&j, &i, sizeof(int));
printf("Source: i = %d, dest: j = %d\n", i,j);
j = 100;
memcpy(&i, &j, sizeof(int));
printf("Source: j = %d, dest: i = %d\n", j,i);
return 0;
compiled with just a warning:
warning: passing argument 1 of ‘memcpy’ discards ‘const’ qualifier
from pointer target type [enabled by default]
But did run just fine, and changed the value of a const variable.
Attempt to modify the value of a const-qualified variable leads to an undefined behavior in C. You should not rely on your results, since anything can happen.
C11 (n1570), § 6.7.3 Type qualifiers
If an attempt is made to modify an object defined with a const-qualified type through use
of an lvalue with non-const-qualified type, the behavior is undefined.
Nothing force the compiler to produce a diagnostic message.
In fact, this qualifier has not enormous effects on the machine code. A const-qualified variable does not usually reside in a read-only data segment (obviously, not in your implementation, although it could be different on an other one).
The compiler can't tell easily what a pointer is pointing to in a given function. It is possible with some static analysis tools, which perform pointer-analysis. However, it is difficult to implement, and it would be stupid to put it in the standard.
The question asks why. Here's why:
This is allowed because once you have a pointer to a memory address, the language does not know what it points to. It could be a variable, part of a struct, the heap or the stack, or anything. So it cannot prevent you from writing to it. Direct memory access is always unsafe and to be avoided if there's another way of doing it.
The const stops you modifying the value of a const with an assignment (or increment etc). This kind of mutation is the only operations it can guarantee you won't be able to perform on a const.
Another way to look at this is the division of the static context (i.e. at compile time) and the runtime context. When you compile a piece of code which may, for example, make an assignment to a variable, the language can say "that's not allowed, it's const" and that is a compilation error. After this, the code is compiled into an executable and the fact that it is a const is lost. Variable declarations (and the rest of the language) is written as input to the compiler. Once it is compiled, the code isn't relevant. You can do a logical proof in your compiler to say that consts aren't changed. The compiled program runs, and we know at compile time that we have created a program that doesn't break the rules.
When you introduce pointers, you have behaviour that can be defined at run-time. The code that you wrote is now irrelevant, and you can [attempt to] do what you want. The fact that pointers are typed (allowing pointer arithmetic, interpreting the memory at the end of a pointer as a particular type) means that the language gives you some help, but it can't prevent you from doing anything. It can make no guarantees, as you can point a pointer anywhere. The compiler can't stop you breaking the rules at run-time with code that uses pointers.
That said, pointers are the way we get dynamic behaviour and data structures, and are necessary for all but the most trivial code.
(The above is subject to lots of caveats, i.e. code heuristics, more sophisticated static analysis bus is broadly true of a vanilla compiler.)
The reason why is because the C language allows any pointer type to be implicitly casted to/from the type void*. It is designed that way because void pointers are used for generic programming.
So a C compiler is not allowed to stop your code from compiling, even though the program invokes undefined behavior in this case. A good compiler will however give a warning as soon as you implicitly try to cast away a const qualifier.
C++ has "stronger typing" than C, meaning that it would require an explicit cast of the pointer type for this code to compile. This is one flaw of the C language that C++ actually fixed.
While 'officially' it's undefined in reality it's very much defined - you will change the value of the const variable. Which raises the question why it's const to begin with.

Resources