Why is this code on array of structures working? - c++

This code on array of structures is working but according to my understanding it shoudn't.
Code:
#include<stdio.h>
#include<string.h>
int main()
{
struct virus {
char signature[25];
char status[20];
int size;
} v[2] = {
"Yankee Doodle", "Deadly", 1813,
"Dark Avenger", "Killer", 1795
};
for(int i=0;i<=1;i++) {
printf("%s %s\n", &v[i].signature, &v[i].status);
}
return 0;
}
According to me, when we try to access the members of a structure using the address of an instance of the structure, we must use the -> operator rather than the . operator. I know that we do it only in case a pointer,but as far as I know, array is functionally equivalent to a pointer. Please help me where I am going wrong with my concepts. And pardon my silly question, because I am just a beginner.

It should not according to Operator Precedence. [] has higher precedence than ., and . has higher precedence than &. So &v[i].signature is equivalent to & ( (v[i]).signature). So first the ith item is taken from v, then it's signature member is accessed, which is a character array, and then & is applied which gives the address of the character array.
It works in VS, but this is not standard behavior.

It doesn't really work. You probably expected &v[i].signature to be (&v[i]).signature (which should have been (&v[i])->signature), but it's actually &(v[i].signature), of type char (*)[25]. If the program still produces the expected output, then that's purely by chance.
GCC would have told you this even without -Wall:
$ gcc -c a.c
a.c: In function ‘main’:
a.c:18:9: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char (*)[25]’ [-Wformat=]
printf("%s %s\n",&v[i].signature,&v[i].status);
^
a.c:18:9: warning: format ‘%s’ expects argument of type ‘char *’, but argument 3 has type ‘char (*)[20]’ [-Wformat=]

It's working because:
&v[i].signature == &v[i] == v->signature
(&v).signature == v->signature
You have taken the address using & and dereferenced using [].

Related

Array subscript out of bounds when struct has zero length array as only member

In the following code:
#include <cstring>
template <unsigned len>
struct CharArray {
CharArray() {
memset(data_, 0, len);
}
char data_[len];
};
struct Foobar {
CharArray<5> a;
CharArray<3> b;
CharArray<0> c;
};
int main() {
Foobar f;
}
The type CharArray<0> ends up having a zero-sized array as its only member. I'm aware of this being a GCC extension and unsafe practice in general. The question is not about that.
When I compile the code with gcc 10.2.0, I get the following warning:
<source>: In function 'int main()':
<source>:5:3: warning: array subscript 8 is outside array bounds of 'Foobar [1]' [-Warray-bounds]
5 | CharArray() {
| ^~~~~~~~~
<source>:18:10: note: while referencing 'f'
18 | Foobar f;
| ^
With gcc9 and earlier there's no warning.
Question: Where does the subscript 8 come from? And what is the Foobar [1] mentioned there? It looks like there's an array of one Foobars and we're trying to access element 8 in that array. Not sure how that could happen. If somebody knows the details, I'd appreciate it if you could explain it.
This happens when compiling with gcc++-10 in Ubuntu 20.04 with -O3 -Wall -Wextra as options. If I don't pass any optimization flag, there won't be any warning. Also: if I take the constructor away, the warning will also disappear.
It seems the issue is somehow related to the memset(): as avoiding it using a condition (len != 0) doesn't work it seems the compiler recognizes that the start address of CharArray<0>'s object is produced by the intialization of CharArray<3> and warns about that. This theory can be tested by conditionally not initializing CharArray<3> with memset() or specializing that type as that makes the warning go way:
CharArray() { if (len != 3) memset(data_, 0, len); }
or
template <>
struct CharArray<3> {
CharArray(): data_() { }
char data_[3];
};
The warning is probably spurious. It seems by the time the address of the zero sized array is used the compiler has "forgotten" that it was produced by accessing a different array's member. The easiest approach to avoid the warning seems to correctly initialize the data in the initializer list and not using memset() at all:
template <unsigned len>
struct CharArray {
CharArray(): data_() {}
char data_[len];
};
Doing anything to a zero length C-like array is higly suspicious. Including even defining one in my opinion.
However, you can specialise the constructor to NOT do anything to the zero length array:
template<> CharArray<0>::CharArray() {}
In order to not even define a zero sized array (which I think should not be an obstacle to anythign you might want to achieve with the class in general...), you would have to specialise the whole class. (credits to Dietmar Kühl for this addition)

Compiler showing warning during compilation of the following code [duplicate]

This question already has answers here:
warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘char (*)’
(3 answers)
Closed 5 years ago.
#include<stdio.h>
int main()
{
char str[6][50] ; // a 2d character array
int i ;
for(i = 0 ; i < 6 ; i++)
{
scanf("%s",(str+i)) ; // in here the warning was shown
}
return 0 ;
}`
During Output :-
scanf() is showing warning on compilation - warning: format ‘%s’ expects argument of type ‘char ’, but argument 2 has type ‘char ()[50]’ [-Wformat=]
Remember that arrays naturally decays to pointers to their first element? That means str by itself is treated as a pointer. With str + i you are doing pointer arithmetic, the result of which is another pointer (to the i:th element in this case). The type of that pointer is a pointer to an array, char (*)[50], it's not the array itself.
What you need to do is to dereference the pointer: *(str + i). Or as it's the same, str[i].
It seems like you are trying to access each element of str in turn. To do this use scanf("%s",str[i]); (as per usr's comment).

Array initialization from non-constexpression

I am trying to understand an example taken from the C++ Primer Book regarding array initialization.
They say that
The number of elements in an array is part of the array’s type. As a result, the dimension must be known at compile time, which means that the dimension must be a constant
expression
An example follows which is supposed to result in an error:
unsigned cnt = 42; // not a constant expression
string bad[cnt]; // error: cnt is not a constant expression
However, compiling this with g++ 4.8.4 does not result in an error.
Is this an error or outdated information in the book, or is it just a g++ feature?
Yes, it should be a g++ feature.
It will emit a warning when -pedantic option is used.
test program
#include <string>
using std::string;
int main(void){
unsigned cnt = 42; // not a constant expression
string bad[cnt]; // error: cnt is not a constant expression
return 0;
}
result on Wandbox
prog.cc: In function 'int main()':
prog.cc:6:19: warning: ISO C++ forbids variable length array 'bad' [-Wvla]
string bad[cnt]; // error: cnt is not a constant expression
^
I think it is worth to talk about "alloca" here. This is how those types of arrays are implemented. Of course they have their limitations like size of operator is not supported for them. You can check details: http://man7.org/linux/man-pages/man3/alloca.3.html

Why can a const value not be changed in C++ but in C? [duplicate]

This question already has answers here:
how to avoid changing value of const in C
(4 answers)
Closed 8 years ago.
In an interview, I was asked to change constant value in CPP, but I said in CPP it is not possible but in c it is possible using pointer.
Interviewer said that using CPP it is possible and asked me to try but I couldn't and I came back to my room and tried again but what I figured out that I was able to change in C but same code was getting error when compiled as C++.
#include<stdio.h>
main()
{
const int i=5;
int *p;
p=&i;
*p=8;
printf("%d",i);
}
This code is changing the constant value of i in c but when I compile in CPP then
I get an error:
invalid conversion from 'const int*' to 'int*'
Given your error, the actual program must have been the following:
#include<stdio.h>
main()
{
const int i=5;
int *p;
p=&i;
*p=8;
printf("%d",i);
}
This produces a warning with gcc:
warning: assignment discards 'const' qualifier from pointer target type
and an error with g++:
error: invalid conversion from 'const int*' to 'int*'
So, let's change the title of your question to a better one:
Why does C allow conversion from const int * to int *, but C++ doesn't?
The reason why one gives a warning and another gives an error is not because one allows you to discard const qualifier and the other doesn't. It's merely because the C standard leaves such incorrect actions as undefined behavior, while the C++ standard specifically marks it as an error. Either way, doing this is wrong.
You can read this similar question asking why this is possible in C.
What I think interviewer wanted this:
int n = 0;
int const *p = &n;
The expression &n has type “pointer to int.” The declaration for p converts &n to type “pointer to const int,” adding a const qualifier in the process. This is a valid qualification conversion. This conversion in no way invalidates n’s declaration. The program can still use n to alter the int object, even if it can’t use *p for the
same purpose.
*p = 5; // wrong
But
n = 5; // OK
now *p is 5 although it is const type!
Now try to run this code in GCC or g++, it will work:
#include<stdio.h>
int main()
{
int n = 0;
const int *p;
p=&n;
printf("%d\n",*p);
n = 5;
printf("%d\n",*p);
return 0;
}
EDIT: The only way to change the value of const qualified object in C and C++ both is, change the value in the initialization statement:
const int i = 5 ---> const int i = 8
This is why const_cast exists, I believe the interviewer asked this because they have to deal with poorly designed library code they have no control over, however normally you shouldn't have to resort to using it in production.

sizeof operator giving error

#include<stdio.h>
int main()
{
printf("\nsize of int : %d", sizeof int);
return 0;
}
is returning error
error: expected expression before ‘int’
while compiling with C
and
expected primary-expression before ‘int’
while compiling with C++, but the following codes works just fine.
#include<stdio.h>
int main()
{
int b;
printf("\nsize of int : %d", sizeof b);
;
return 0;
}
Why is it so? What is the difference in both the cases?
sizeof needs parentheses when used with a type. They're optional with an expression.
Your code would then become:
printf("\nsize of int : %zu", sizeof(int));
Thanks to #Grijesh, I've also used the right format specifier for size_t. If this format specifier causes problems (likely related to Windows), the next best would probably be %lu.
You forgot the brackets(). When you are using sizeof with a type you need brackets. Try this:
printf("\nsize of int : %zu", sizeof(int));
You may also use the format specifier %lu when %zu is not available in microsoft compilers.
The sizeof operator is used to determine the amount of space a designated datatype would occupy in memory. To use sizeof, the keyword "sizeof" is followed by a type name or an expression (which may be merely a variable name). If a type name is used, it must always be enclosed in parentheses, whereas expressions can be specified with or without parentheses.
char c;
printf("%zu,%zu\n", sizeof c, sizeof (int));