Asked  7 Months ago    Answers:  5   Viewed   1.9k times

I'm a beginner C programmer, yesterday I learned the use of C structs and the possible application of these ones about the resolution of specific problems. However when I was experimenting with my C IDE (Codeblocks 16.01) in order to learn this aspect of C programming, I've encountered a strange issue. The code is the following:

#include <stdio.h>

#define N 30

typedef struct{
     char name[N];
     char surname[N];
     int age;
} data;

int main() {
     data s1;
     s1.name="Paolo";
     s1.surname = "Rossi";
     s1.age = 19;
     getchar();
     return 0;
}

During the compilation, the compiler (GCC 4.9.3-1 under Windows) reported me an error that says

"error: assignment to expression with array type error"

on instruction

s1.name="Paolo" 
s1.surname="Rossi" 

while if I do

data s1 = {"Paolo", "Rossi", 19};

it works. What am I doing wrong?

 Answers

47

You are facing issue in

 s1.name="Paolo";

because, in the LHS, you're using an array type, which is not assignable.

To elaborate, from C11, chapter §6.5.16

assignment operator shall have a modifiable lvalue as its left operand.

and, regarding the modifiable lvalue, from chapter §6.3.2.1

A modifiable lvalue is an lvalue that does not have array type, [...]

You need to use strcpy() to copy into the array.

That said, data s1 = {"Paolo", "Rossi", 19}; works fine, because this is not a direct assignment involving assignment operator. There we're using a brace-enclosed initializer list to provide the initial values of the object. That follows the law of initialization, as mentioned in chapter §6.7.9

Each brace-enclosed initializer list has an associated current object. When no designations are present, subobjects of the current object are initialized in order according to the type of the current object: array elements in increasing subscript order, structure members in declaration order, and the first named member of a union.[....]

Wednesday, June 2, 2021
 
capsid
answered 7 Months ago
75

The call fails with the same reason the following will also fail:

string foo = string.Format("{0} {1}", 5);

You are specifying two arguments in the format but only specifying one object.

The compiler does not catch it because int[] is passed as an object which is a perfectly valid argument for the function.

Also note that array covariance does not work with value types so you cannot do:

object[] myInts = new int[] {8,9};

However you can get away with:

object[] myInts = new string[] { "8", "9" };
string bar = string.Format("{0} {1}", myInts);

which would work because you would be using the String.Format overload that accepts an object[].

Wednesday, August 11, 2021
 
hakimoun
answered 4 Months ago
59

The stack does not unwind when you 'kill' a thread.

Killing threads is not a robust way to operate - resources they have open, such as files, remain open until the process closes. Furthermore, if they hold open any locks at the time you close them, the lock likely remains locked. Remember, you are likely calling a lot of platform code you do not control and you can't always see these things.

The graceful robust way to close a thread is to interrupt it - typically it will poll to see if it's been told to close down periodically, or it's running a message loop and you send it a quit message.

Thursday, August 12, 2021
 
The Coding Wombat
answered 4 Months ago
39

There are lots of problems with your code.

  1. scanf("%s", &dest_in) will read a string into dest_in which could potentially overflow your buffer because there is no size specifier. Consider changing it to scanf("%99s", dest_in) so you read 99 characters maximum, + 1 for the null terminator which is 100 (your array size). Also, there is no need to use to & operator here.

  2. travel_name[i][0]=dest_in[100]; You are accessing a character that is outside the bounds of dest_in. The only index you should access is 0.

  3. printf("Trip#:%d travel_name:%s n", row+1, travel_name[row][col]); Your code says that you want to print a string. printf goes looking for a pointer to a character array but travel_name[row][col] is a single character.

  4. while (trip_num > TRIP). You tell the user to enter a number between 3 and 6 but you don't check if the input is less than 3.

Friday, September 3, 2021
 
Jonathan Taylor
answered 3 Months ago
41

To clarify usr's correct but somewhat sparse answer:

C# supports a feature -- my candidate for "worst feature in C#" -- called array type covariance. That is, if you have an array of turtles, you can assign it to a variable of type "array of animals":

class Animal {}
class Turtle : Animal {}
...
Animal[] animals = new Turtle[10];

This is "covariance" because the assignment compatibility rule for arrays is an arrow in the same direction as the assignment compatibility rule for its elements:

Turtle --> Animal
Turtle[] --> Animal[]

This is feature is not type safe because, well...

animals[0] = new Giraffe();

And we just put a giraffe into an array that is actually an array of turtles. The compiler cannot determine that type safety is violated here -- a giraffe is an animal -- so the check has to be performed by the runtime.

To prevent this from happening at runtime, the runtime inserts a check every time you put a Giraffe into an array of Animals to check if it is really an array of Turtles. Which it almost never is. But this check takes time, and so the feature effectively slows down every successful array access.

Unsafe array covariance only applies to arrays whose element types are reference types. It does not apply to value types. (This is a small lie; the CLR will allow you to cast int[] to object and then object to uint[]. But in general, covariance does not apply to value types.)

Therefore you can save on the expense of the check by making your array actually an array of value type, where the value type is just a wrapper for the reference. The size of the array will be unaffected, but the access to it will be slightly faster.

You should not pull these sorts of crazy tricks unless you have empirical evidence that doing so actually solves a practical performance problem. The number of situations in which this optimization is warranted is quite small, but there are a few places where this sort of thing can make a difference.

I note that you can also avoid the cost of the check by sealing the Turtle type and then using an array of Turtles. The runtime will reason that the array type cannot really be more derived because then its element type would derive from a sealed type, which is impossible.

Sunday, November 7, 2021
 
BradM
answered 4 Weeks ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share