function with a struct array pointer as an argument, C language - c

typedef struct {
char manufacturer[SIZE];
char model[SIZE];
int size;
int id;
int qty;
double cost;
double price;
} tv;
void firstSix(tv *tvarr[]);
void firstSix(tv *tvarr[])
{
(*tvarr[0]).manufacturer = "Vizio";
}
I am making an inventory program. It consists of an array of structs that will store information about different televisions. In my program I am required to hardcode six entries into the array, so I am trying to make a function that will take a struct array pointer argument. In the above code, I included the struct declaration, the function prototype and function definition that I am trying to make. Everything is placed before and after main in the respective order. I don't understand why Visual Studio is highlighting the first parenthesis in the code inside the function definition and saying "expression must be a modifiable lvalue". I don't understand what it is that I am doing wrong. Please help.

You cannot assign an array like that. You need to do
strcpy ((*tvarr[0]).manufacturer, "Vizio");
Make sure that you don't go out of bounds when copying the string into the array.
You can either check the size of the string in advance or use strncpy which will limit the maximum number of characters to be copied.
An array is not a modifiable l-value. So basically you cannot have it on the left hand side of an assignment.
Or may be you also might want to define manufacture as char *manufacture and then dynamically allocate the string.
manufacturer = strdup ("Vizio"); //manufacturer is char *
Or depending on the length first allocate the buffer
manufacturer = malloc (sizeof (char) * needed_bytes);
Whenever you dynamically allocate the buffer, whenever you have finished working with it always remember to free it free (manufacturer).

I think you want to do something like
strncpy((tvarr[0])->manufacturer, "Vizio", SIZE - 1);
Kevin has it; you can't assign a string to a pointer, you must copy the data to the array. I suggest strncpy to keep from running off the end of the allocated space.

Related

Re: Struct Array with Varying Size Structs--Clarification

I have a question regarding one of the solutions that was posted--the accepted one on this thread:
https://stackoverflow.com/a/4982586/5854333 .
I would have left a comment on it instead of starting a new question thread, but I do not currently have the experience necessary. The program indeed runs as promised and is similar to what I intend to actually implement, but I'm still confused as to whether there may be subtle memory issues in it.
For example, in the portion:
void addStringToHolder(stringHolder * holder, const char * string) {
char ** newStrings = realloc(holder->strings, newStringCount * sizeof(char *));
if (newStrings != NULL) {
holder->strings = newStrings;
}
}
(we are working in this function with the struct)
typedef struct {
int numberOfStrings;
char ** strings;
}stringHolder;
Can the double pointer strings really be modified in this function? I thought we always had to pass in a pointer to the thing we wanted to modify, rather than the thing itself. Wouldn't we have to pass in a triple pointer if we wanted to modify the double pointer?
Of course we are also passing in a pointer to the struct in the first place, so does that make this work? I think I'm getting lost in all of these pointers. A little clarity would be helpful. Hopefully understanding this case will allow me to understand the others.
Can the double pointer strings really be modified in this function?
Shortly, yes.
To elaborate:
A pointer in C is just a location in the memory, when you pass it to a function you simply tell the function where to preform its operation.
By passing in a pointer to the struct, we are calling all of its elements by reference, and thus we can modify any of its elements, including the double pointer strings.
Say we have a pointer to your struct stringHolder* h_ptr where:
typedef struct {
int numberOfStrings;
char ** strings;
}stringHolder;
Now using * to dereference the pointer(s) you can access every level:
h_ptr /*some adress in memory*/
*h_ptr /*the value stored in said adress (we know its a stringHolder)*/
using the syntax x->y instead of (*x).y for readability
h_ptr->numberOfStrings /*the integer value stored in this struct*/
h_ptr->strings /*a pointer to an array of C string pointers*/
*(h_ptr->strings) /*the first "string" in said array, same as saying
a pointer to the first char in the first "string"*/
**(h_ptr->strings) /*the first char of the first "string"*/
And with pointer arithmetic we can get wherever we want and modify the values (as long as we keep the C convention of null terminated strings)
*(h_ptr->strings + 1) /*the second "string" in strings array*/
*(*(h_ptr->strings + 2) + 4) /*the fifth char in the third "string"*/
and so on.

How should I declare strings within C structs?

Hello I am new to this site, and I require some help with understanding what would be considered the "norm" while coding structures in C that require a string. Basically I am wondering which of the following ways would be considered the "industry standard" while using structures in C to keep track of ALL of the memory the structure requires:
1) Fixed Size String:
typedef struct
{
int damage;
char name[40];
} Item;
I can now get the size using sizeof(Item)
2) Character Array Pointer
typedef struct
{
int damage;
char *name;
} Item;
I know I can store the size of name using a second variable, but is there another way?
i) is there any other advantage to using the fixed size (1)
char name[40];
versus doing the following and using a pointer to a char array (2)?
char *name;
and if so, what is the advantage?
ii) Also, is the string using a pointer to a char array (2) going to be stored sequentially and immediately after the structure (immediately after the pointer to the string) or will it be stored somewhere else in memory?
iii) I wish to know how one can find the length of a char * string variable (without using a size_t, or integer value to store the length)
There are basically 3 common conventions for strings. All three are found in the wild, both for in-memory representation and storage/transmission.
Fixed size. Access is very efficient, but if the actual length varies you both waste space and need one of the below methods to determine the end of the "real" content.
Length prefixed. Extra space is included in the dynamically allocation, to hold the length. From the pointer you can find both the character content and the length immediately preceding it. Example: BSTR Sometimes the length is encoded to be more space efficient for short strings. Example: ASN-1
Terminated. The string extends until the first occurrence of the termination character (typically NUL), and the content cannot contain that character. Variations made the termination two NUL in sequence, to allow individual NUL characters to exist in the string, which is then often treated as a packed list of strings. Other variations use an encoding such as byte stuffing (UTF-8 would also work) to guarantee that there exists some code reserved for termination that can't ever appear in the encoded version of the content.
In the third case, there's a function such as strlen to search for the terminator and find the length.
Both cases which use pointers can point to data immediately following the fixed portion of the structure, if you carefully allocate it that way. If you want to force this, then use a flexible array on the end of your structure (no pointer needed). Like this:
typedef struct
{
int damage;
char name[]; // terminated
} Item;
or
typedef struct
{
int damage;
int length_of_name;
char name[];
} Item;
1) is there any other advantage to using the fixed size (1)
char name[40];
versus doing the following and using a pointer to a char array (2)?
char *name;
and if so, what is the advantage?
With your array declared as char name[40]; space for name is already allocated and you are free to copy information into name from name[0] through name[39]. However, in the case of char *name;, it is simply a character pointer and can be used to point to an existing string in memory, but, on its own, cannot be used to copy information to until you allocate memory to hold that information. So say you have a 30 character string you want to copy to name declared as char *name;, you must first allocate with malloc 30 characters plus an additional character to hold the null-terminating character:
char *name;
name = malloc (sizeof (char) * (30 + 1));
Then you are free to copy information to/from name. An advantage of dynamically allocating is that you can realloc memory for name if the information you are storing in name grows. beyond 30 characters. An additional requirement after allocating memory for name, you are responsible for freeing the memory you have allocated when it is no longer needed. That's a rough outline of the pros/cons/requirements for using one as opposed to the other.
If you know the maximum length of the string you need, then you can use a character array. It does mean though that you will be using more memory than you'd typically use with dynamically allocated character arrays. Also, take a look at CString if you are using C++. You can find the length of the character array using strlen. In case of static allocation I believe it will be a part of the variable. Dynamic can be anywhere on the heap.

Does a function's pointer to char needs memory allocation in C

Defining a function in c using this structures of data:
typedef struct {
int number;
char name[25];
} person;
person rep[100];
int key=0;
Is there any problem with memory allocation when defining this function:
(i'm just a beginner: i don't know what memory allocation means)
void add_person(int num, char *name){
if (key<100){
rep[key].number = num;
strcpy(rep[key].name, name);
key++;
}
}
A function's pointer is something completely different than this.
What you have is a function with a char * (char pointer). If you call this function, you pass it the contents for a "new" person struct.
This person struct contains a (rather small) array where the name can be held, so memory allocation (which means reserving a memory area for dedicated use) is implied there.
But be warned: what do you think will happen if the caller passes a string with more than 25 characters? Right, it will "destroy" the contents of the memory area behind it.
So you'll have to pay attention and use strncpy(rep[key].name, name, sizeof rep[key].name). As the creator of strncpy() seems to have slept ("No null-character is implicitly appended at the end of destination if source is longer than num"), you'll have to add this null-character - which indicates the end of a string in C - by yourself:
rep[key].name[sizeof rep[key].name - 1] = '\0'
If the string was shorter, strcpy() has added its own '\0', if not, we cut it here.
There is no need for any explicit allocations in your code (as shown). The definition
person rep[100];
makes the compiler allocate space for 100 person structures. And with the member-field definition
char name[25];
each person structure have space for 25 characters in name (i.e. a string with up to 24 characters, plus the string terminator).
For your add_person, you don't need to worry about memory leaking.
But you need to either add key as a global variable (next to rep) or define it as a static variable inside of add_person like this:
static int key = 0;
But you have an issue with this line
strcpy(rep[key].name, name);
If the input name to add_person is longer than 24 characters, it will result in strcpy writing outside of rep.name.
At length 25, the name no longer is null-terminated, causing any function reading on that to read past it and (best case) into the next person (their number showing up as either garbage or another random character), or (worst case) outside of the rep array and your program segfaults.
You should check that name is shorter than 25.
The correct thing to do would to have char* name; in function, then do the following copy in add_person:
rep[key].name = malloc( strlen(name)+1 );
strcpy( rep[key].name, name );
In this case, you should make a function to free persons
free_person(struct person* p)
{
free(p->name);
}
your function definition is good
just a thing concerning the key variable: It should be defined as global variable
The line person rep[100]; reserves space for you to store 100 person objects, so no, there isn't a problem with memory allocation.
In real life, you would also need to be more careful that you didn't write a name longer than 24 characters into the name member.

C Multidimensional Character Array Initialization

I'm fairly new to C and I'm trying to wrap my head around the initialization of a multidimensional character array, for my assignment I'm asked to read from a file and store the text in an array,
I have to read input for 5 fictitious people and store some information about them, so I realized that my array will look something like:
char input[5][];
What I am confused about is the second parameter, I'm not sure what to set it too. There are 9 fields of information which I will be storing about these people, and I can't seem to find an answer to if I should set this second number to the amount of fields, or how large it should be. ie,
char input[5][9];
or
char input[5][256];
Also, if it's the latter, is there a practice of how larger I should set it to, or just pick a number? Thanks!
I suggest you take the following approach: instead of making an array of char to store the information about these persons, you should make a struct person, which would have some info variable with predefined lenght
struct person {
char name[50];
char address[50];
char phone_number[15];
};
or, if you want, you can make these char pointers (such like char *name, char *address), and then you can malloc() the desired amount of memory to each variable as you want (also, don't forget to free the memory after you use it).
Then, in your main, you could make an array of persons, such as struct person[5];, and manipulate them as you want.
edit: Also note that, as Pankrates commented, when you define a size for your array you must make sure that the input will not exceed the lenght of the array, otherwise you'll be writing stuff on memory that does not belong to you, which causes undefined behavior.
To figure this you should try to learn about the input. If you are absolutely sure there will be only 9 fields(of single char data) for 5 people, then you should set it to char input[5][9].
If you think there could be more fields of information than 9 in the future, then you could go for a higher value like char input[5][256]. However this would waste a lot of space if the data for fields are sparse. This is static assignment of memory
So the third option when you are unsure about the number of fields for each person, is to assign memory dynamically like--
char* input[5];
input[0] = malloc(sizeof(char) * 100); // space of 100 chars
Here in the last case, the memory is given at runtime instead of compile time. You can also get the size from user input and use it for assign memory for fields.
char* input[5];
int size = 0;
scanf("%d",&size);
input[0] = malloc(sizeof(char) * size);
Further more, if you need to store fields, where each field takes more than one character then you should create a structure.
struct person
{ char name[30]; // memory could be assigned dynamically or statically
char field1[30];
char field2[30];
...
};

Using pointers with functions and structs

Hello i'm selfstudying C and i'm a bit confused about the following code since i don't know if i'm understanding the code properly. I would be very thankful if someone could read my explanation and correct me if i'm wrong.
The code is from a header file. The function of the program should be uninteresting at this point, since my comprehension problem is about the pointers and the values the functions give back. So first of all i'm declaring 3 arrays of char and an integer in my employee struct.
struct employee
{
char firstname[11];
char lastname[11];
char number[11];
int salary;
}
5 functions are declared in the header file. The first function takes 4 values (3 pointers and one int) and gives back a pointer to a struct. The second function gets a pointer to the "struct employee" and gives back a pointer to an element of the array "char firstname" in the struct employee. The functions 3 and 4 are doing the same for the other both arrays. The function 5 gets a pointer to the struct employee but gives back an int and not a pointer. So it is just using the declared variable in the struct.
struct employee* createEmployee(char*, char*, char*, int); //1
char* firstname (struct Employee*); //2
char* lastname (struct Employee*); //3
char* number (struct Employee*); //4
int salary (struct Employee*); //5
Your understanding is pretty much correct. To be a little more accurate and/or less abusive of the English language, functions 2-4 return a pointer to an element of the corresponding array.
The idea is that the contents of each array represent some kind of text, with each element corresponding a character of text, up until the first appearance of a zero value (used to mark the end of the "string"). Keep in mind that there is no provision for Unicode here, or even for specifying an encoding: we assume ASCII, and for any bytes not in the range 0..127, all bets are off. A better name for the type char would be byte; but we didn't really know any better back then. (You should also be aware that char is a separate type from both signed char and unsigned char, and that char may or may not be signed.)
This way, the names and number can be any length up to ten (an 11th byte is reserved in order to have room for the "null terminator" with the zero value), and the returned pointer can be used to inspect - and modify; but that might not be a good idea - the data in the arrays that are part of the Employee structure.
The int returned as the Employee 's salary is a copy of the one in the struct. So although we can see the whole value, this does not let us modify the value in the struct. Of course, as long as we have the struct definition and an Employee instance, there is no protection; we can access the member directly instead of going through the function.
In C, we get "encapsulation" and "data hiding" by not providing these definitions. Instead, we would just put struct Employee; and the function declarations in the header, and the struct definition in the implementation file. Now calling code doesn't know anything about what an Employee is; only about what it can do.
Almost right, except when you read the functions, the input "char*" should be read as a string is passed in though technically it is a pointer. for integers the actual value is passed, so you are right there.
so,
struct employee* createEmployee(char*, char*, char*, int);
would mean that the procedure creates a employee with the four inputs passed (the first three are strings (Char*) which probably are first name, last name and number/id in that order and the last one is the salary.)
What you cannot be sure by just reading the function signature whether the values/pointers returned are reference to same values/pointers from the sturct, or the function(s) is creating a copy and returning pointer to the new value. This is why its a good idea to also write the documentation as comments with the function signature in the header file.
Your explanations make sense, except #2-4: since they return char*, they cannot return an element of a char array (the correct type for the latter would be simply char). Each of the three functions returns a pointer to char. One presumes that they return the pointer to the first element of the corresponding array, which is basically how arrays are passed around in C.
There is a problem in 1. What you're doing I assume is:
struct employee* createEmployee(const char* f, const char* l, const char* n,
const int sal)
{
struct employee* e;
strcpy(e->firstname, f);
strcpy(e->lastname, l);
/* ... */
return e;
}
The problem here is the arrays coming in. It is perfectly feasible for a char array of any size to be passed in; anything over the length of 11 would cause you to start overwriting data at &(e->firstname[0])+11;. Over what? Exactly. You've no idea (and nor have I, it'd be determined at run-time). This could cause some serious problems.
One way around that is to use functions from stdlib.h and string.h i.e. strlen() to test the length of the data being passed in to ensure it fits your field size.
A better method might be to write:
int createEmployee(struct employee* e, const char* f, const char* l, const char* n,
const int sal)
{
int error = 0;
if ( strlen(f) < 11 )
{
strncpy(e->firstname, f);
}
else
{
error++;
}
/* ... */
return error;
}
See what I've done? Yes it will work - anything passed in as a pointer can be modified. It's not pass-by-reference, quite. Edit: as aix says, pointers are "how arrays are passed around in C".
Another potential method is strncpy() which will truncate the source string according to the last argument, so strncpy(e->firstname, f, 11); would be safe.
You might well try dynamic memory allocation for the field sizes based on requirement, too. I'm guessing you'll be learning that later/as another challenge.
Also, another suggestion whilst we're at it is to define the pointer to a struct using typedef. It makes things a little more readable although the way you've done it is definitely clearer for someone learning.

Resources