Passing argument to a struct in C - arrays

I want to create the following struct.
struct student
{
char name[n+1];
int length = n;
};
Where n is a specific integer. Is it possible to pass an argument to a struct or another solution to achieve something like this? Maybe pointers. So I want different structs based on length.

You can use a flexible array member:
struct student {
int length;
char name[];
};
The struct is allocated and initialized for length n with:
struct student *s = malloc(sizeof *s + n + 1);
s->length = n;
// initialize s->name
strcpy(s->name, the_name_of_n_chars);
Remember to call free on s when it is no longer used.

Here is another implementation, apart from the other answers.
#include <string.h>
#include <stdlib.h>
struct student
{
char *name;
int length;
};
struct student *
alloc_student(char *name)
{
struct student *new;
new = malloc(sizeof(struct student));
if (new)
{
new->name = malloc(strlen(name)+1);
if (new->name)
{
new->length = strlen(name);
strcpy(new->name, name);
}
else
{
free(new);
new=NULL;
}
return new;
}
void
dealloc_student(struct student *s)
{
free(s->name);
free(s);
}
int
main(void)
{
struct student *s0;
s0 = alloc_student("John");
if (s0) dealloc_student(s0);
return 0;
}

Here is a way to have something like parameterized types, but I would not recommend that you do this! As you can see in the example below, it may not give you what you want and no extra safety. Better use the solution from tstanisl's answer.
You could use the C preprocessor to get different kinds of student structs with name arrays of different sizes. However, these will be distinct struct types, so the type of a student20 with char name[20 + 1] is related to the type of a student30 with char name[30 + 1].
#include <string.h>
#include <stdio.h>
#define DEFSTUDENT(n) struct student##n { \
char name[n+1]; \
int length; \
}
#define STUDENT(n) struct student##n
#define INIT_STUDENT(name) { name, strlen(name) }
DEFSTUDENT(100) student1 = INIT_STUDENT("John");
DEFSTUDENT(20) student2 = INIT_STUDENT("James");
DEFSTUDENT(1);
int main()
{
STUDENT(20) student3 = INIT_STUDENT("");
printf("%d\n", student3.length);
printf("%d\n", student2.length);
STUDENT(1) impossibleStudent = INIT_STUDENT("Walter");
printf("%d %s\n", impossibleStudent.length, impossibleStudent.name);
}
Note what the preprocessor makes out of this (I removed the #includes here for clarity):
C:\cygwin64\tmp\preproc>gcc -E student.c
# 1 "student.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "student.c"
# 11 "student.c"
struct student100 { char name[100 +1]; int length; } student1 = { "John", strlen("John") };
struct student20 { char name[20 +1]; int length; } student2 = { "James", strlen("James") };
struct student1 { char name[1 +1]; int length; };
int main()
{
struct student20 student3 = { "", strlen("") };
printf("%d\n", student3.length);
printf("%d\n", student2.length);
struct student1 impossibleStudent = { "Walter", strlen("Walter") };
printf("%d %s\n", impossibleStudent.length, impossibleStudent.name);
}
Here is what happens when I compile and run it:
C:\cygwin64\tmp\preproc>gcc student.c
student.c: In function 'main':
student.c:22:49: warning: initializer-string for array of chars is too long
STUDENT(1) impossibleStudent = INIT_STUDENT("Walter");
^
student.c:11:30: note: in definition of macro 'INIT_STUDENT'
#define INIT_STUDENT(name) { name, strlen(name) }
^~~~
student.c:22:49: note: (near initialization for 'impossibleStudent.name')
STUDENT(1) impossibleStudent = INIT_STUDENT("Walter");
^
student.c:11:30: note: in definition of macro 'INIT_STUDENT'
#define INIT_STUDENT(name) { name, strlen(name) }
^~~~
C:\cygwin64\tmp\preproc>a.exe
0
5
6 Wa#

Related

Why does my char array not print anything?

In c I am trying to assign a char array inside a struct with a user provided value, here is my code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct person
{
char name[20];
int age;
};
struct person *assign(char arr[], int age)
{
struct person *x = malloc(sizeof(struct person));
x->name[20] = arr[20];
x->age = 21;
return x;
}
int main()
{
char name[20] = "Arthur morgan";
int age = 34;
struct person* person1 = assign(name, age);
printf("name: %s\n", person1->name);
printf("age: %d\n", person1->age);
return 0;
}
The problem is that the name prints nothing for some reason, the age however prints as expected.
Why is the name not printing correctly?
x->name[20] = arr[20];
It does not copy the array
It copies 1 character and you are accessing array outside its bounds which is undefined behaviour (UB)
It is better to use objects not types in sizeof
Always check the result of malloc
You need to copy the string using strcpy function
struct person *assign(char arr[], int age)
{
struct person *x = malloc(sizeof(*x));
if(x)
{
strcpy(x->name,arr);
x->age = 21;
}
return x;
}
https://godbolt.org/z/vKddb4b9a

Why do I keep getting "error: variable has incomplete type 'struct intVec'?

I'm doing an assignment for my data structures class and I have very little experience with C structures and C in general.
This is the .h file that I was given to do the assignment:
#ifndef C101IntVec
#define C101IntVec
typedef struct IntVecNode* IntVec;
static const int intInitCap = 4;
int intTop(IntVec myVec);
int intData(IntVec myVec, int i);
int intSize(IntVec myVec);
int intCapacity(IntVec myVec);
IntVec intMakeEmptyVec(void);
void intVecPush(IntVec myVec, int newE);
void intVecPop(IntVec myVec);
#endif
This is the .c implementation that I've made:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "intVec.h"
typedef struct IntVecNode {
int* data;
int sz; // Number of elements that contain data
int capacity; // How much is allocated to the array
} IntVecNode;
typedef struct IntVecNode* IntVec;
//static const int intInitCap = 4;
int intTop(IntVec myVec) {
return *myVec->data;
}
int intData(IntVec myVec, int i) {
return *(myVec->data + i);
}
int intSize(IntVec myVec) {
return myVec->sz;
}
int intCapacity(IntVec myVec) {
return myVec->capacity;
}
IntVec intMakeEmptyVec(void) {
IntVec newVec = malloc(sizeof(struct IntVecNode));
newVec->data = malloc(intInitCap * sizeof(int));
newVec->sz = 0;
newVec->capacity = intInitCap;
return newVec;
}
void intVecPush(IntVec myVec, int newE) {
if (myVec->sz >= myVec->capacity) {
int newCap = myVec->capacity * 2;
myVec->data = realloc(myVec->data, newCap * sizeof(int));
} else {
for (int i = 0; i < myVec->capacity; i++) {
*(myVec->data + i) = *(myVec->data + i + 1);
}
myVec->data = &newE;
}
myVec->sz++;
}
void intVecPop(IntVec myVec) {
for (int i = 0; i < myVec->capacity; i++) {
*(myVec->data - i) = *(myVec->data - i + 1);
}
myVec->sz--;
}
This is the test file:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "intVec.c"
int main() {
struct IntVec v;
v.intVecPush(v,0);
return 0;
}
Every time I run the test file, I get the error:
test.c:7:16: error: variable has incomplete type 'struct IntVec'
struct IntVec v;
^
test.c:7:9: note: forward declaration of 'struct IntVec'
struct IntVec v;
^
1 error generated.
I've tried changing the #include "intVec.c" to "intVec.h" in the test file, however that produces the same error. What would I need to change in order to not get this error?
There is no structure definition struct IntVec.
So the compiler is unable to define the object v
struct IntVec v;
I think you mean
IntVec v;
And this call
v.intVecPush(v,0);
is invalid and does not make sense. I think there should be something like
IntVec v = intMakeEmptyVec();
intVecPush(v,0);
instead of
struct IntVec v;
v.intVecPush(v,0);
Also it is a bad idea to include the whole module in another module. You should place the structure definition in the header and include this header in the compilation unit with main.
That is move these definitions
typedef struct IntVecNode {
int* data;
int sz; // Number of elements that contain data
int capacity; // How much is allocated to the array
} IntVecNode;
typedef struct IntVecNode* IntVec;
in the header.

How to allocate memory with different type in C?

I have the following code in C:
typedef struct
{
int age;
int phoneNumber;
} Student;
typedef struct
{
int id;
int student[1];
} People;
#define NUM_OF_PEOPLE
void *p = malloc(sizeof(People) + sizeof(int) * NUM_OF_PEOPLE + sizeof(Student) * NUM_OF_PEOPLE);
How could I find the pointer to the memory point to the first element of struct Student in the memory?
I try to do it in the following way:
int i = 0;
for(i = 0; i < NUM_OF_PEOPLE; i++)
{
Student * student_p = p.student[NUM_OF_PEOPLE];
}
It does not work, so can we allocate memory in the way?
And how to find the first element of struct Student in the memory?
What you have is an ancient way of having a flexible array member, which was technically also undefined behavior.
You are looking for this.
First, you need to define your struct like this (I don't know what the ints before the Students are, so let's just call it id):
typedef struct
{
int age;
int phoneNumber;
} Student;
typedef struct
{
int id;
Student student;
} StudentAndId;
typedef struct
{
int id;
StudentAndId students[];
} People;
Note the lack of size in the array inside People. Now you do this:
People *p = malloc(sizeof(People) + sizeof(StudentAndId[NUM_OF_PEOPLE]));
Then you can access students inside p as if it was an array of NUM_OF_PEOPLE elements.
Remember to compile with C99 (or C11) support. With gcc that would be -std=c99 or -std=gnu99.
This will allocate memory for storing the date but how you access it depends on how you store date. using C pointers you can store and access data using this structure and allocation but accessing the members will not be direct. it will involve pointer arithmetic. So better to use other structure if possible. If using this way of allocation then you need to do pointer arithmetic to get the next elements.
Try this:
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int age;
int phoneNumber;
} Student;
typedef struct
{
int id;
int student[1];
} People;
#define NUM_OF_PEOPLE 10
int main()
{
People *p = malloc(sizeof(People) + sizeof(int) * NUM_OF_PEOPLE + sizeof(Student) * NUM_OF_PEOPLE);
int* id = (int*)(p+1);
Student* s = (Student*)(id+NUM_OF_PEOPLE);
printf("Size of People : %d\n", sizeof(People));
printf("p points to : %p\n", p);
printf("id points to : %p\n", id);
printf("s points to : %p\n", s);
}
Here's a sample output:
Size of People : 8
p points to : 0x80010460
id points to : 0x80010468
s points to : 0x80010490
You may want to add the id field to your Student data structure, e.g.:
typedef struct {
int id;
int age;
int phoneNumber;
} Student;
Then, you can define a structure having a fixed header (in this case, this can be the number of students), followed by a variable-sized array of Students:
#define ARRAY_OF_ANY_SIZE 1
typedef struct {
int count;
Student students[ARRAY_OF_ANY_SIZE];
} People;
This blog post explains this technique of having "arrays of size 1", including a discussion of the alignment problem.
I won't repeat the original blog post code here. Just consider that you can use the portable offsetof() instead of the Windows-specific FIELD_OFFSET() macro.
As a sample code, you may want to consider the following:
#include <stdio.h> /* For printf() */
#include <stddef.h> /* For offsetof() */
#include <stdlib.h> /* For dynamic memory allocation */
typedef struct {
int id;
int age;
int phoneNumber;
} Student;
#define ARRAY_OF_ANY_SIZE 1
typedef struct {
int count;
Student students[ARRAY_OF_ANY_SIZE];
} People;
int main(int argc, char* argv[]) {
People* people;
const int numberOfStudents = 3;
int i;
/* Dynamically allocate memory to store the data structure */
people = malloc(offsetof(People, students[numberOfStudents]));
/* Check memory allocation ... */
/* Fill the data structure */
people->count = numberOfStudents;
for (i = 0; i < numberOfStudents; i++) {
people->students[i].id = i;
people->students[i].age = (i+1)*10;
people->students[i].phoneNumber = 11000 + i;
}
/* Print the data structure content */
for (i = 0; i < people->count; i++) {
printf("id: %d, age=%d, phone=%d\n",
people->students[i].id,
people->students[i].age,
people->students[i].phoneNumber);
}
/* Release the memory allocated by the data structure */
free(people);
return 0;
}
Output:
id: 0, age=10, phone=11000
id: 1, age=20, phone=11001
id: 2, age=30, phone=11002

creating, passing, getting back Array of a Struct and loop throuh it in C

I need to execute a function that returns array of a specified struct with variable length. Then I should loop through the returned array.
example struct :
typedef struct student {
int id;
char *name;
int grade;
} Student;
function prototypes 1 :
Student *students;
students = findStudentByGrade(int grade);
function prototypes 2 :
Student *students;
int retval = findStudentByGrade(&students, int grade);
I am bit confused on above methods. How can correctly define a array of struct? call function ? and loop through it untill end? Can some one help me please.
You can do this in this way. This code is working. I tested in CodeLite.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct student {
int id;
char *name;
} Student;
Student *findStudent(int *asize, const int grade);
int main(void)
{
Student *stds;
int asize = 0;
stds = findStudent(&asize, 5);
int i;
for (i = 0; i < asize; i++) {
printf("ID : %i\n", stds[i].id);
}
return 0;
}
Student *findStudent(int *asize, const int grade)
{
struct student *stds = malloc(sizeof(struct student) * 3);
stds[0].id = 10;
stds[1].id = 20;
stds[2].id = 40;
*asize = 3;
return stds;
}
Get the array of struc as returned statement and pass an int variable with argument list to get the size back and simply loop through using a for loop. Or else you will find problem in looping. It is more easy to get the array size from the function which create the array.
I mean this is quite a basic question, but:
Defining array of your structures would look like:
int size = ...;
Student *students = (Student*) malloc(sizeof(Student) * size);
Then just pass that to the function (both size and the array) and then just loop until i < size.
Ofcourse, don't forget to:
free(students);
at the end.

Instantiations for structs in C?

So I'm trying to learn C right now, and I have some basic struct questions I'd like to clear up:
Basically, everything centers around this snippet of code:
#include <stdio.h>
#include <stdlib.h>
#define MAX_NAME_LEN 127
const char* getName(const Student* s);
void setName(Student* s, const char* name);
unsigned long getStudentID(const Student* s);
void setStudentID(Student* s, unsigned long sid);
int main(void) {
Student sarah;
const char* my_name = "Sarah Spond";
setName(&sarah, my_name);
printf("Name is set to %s\n", sarah.name);
}
typedef struct {
char name[MAX_NAME_LEN + 1];
unsigned long sid;
} Student;
/* return the name of student s */
const char* getName (const Student* s) { // the parameter 's' is a pointer to a Student struct
return s->name; // returns the 'name' member of a Student struct
}
/* set the name of student s
If name is too long, cut off characters after the maximum number of characters allowed.
*/
void setName(Student* s, const char* name) { // 's' is a pointer to a Student struct | 'name' is a pointer to the first element of a char array (repres. a string)
int iStringLength = strlen(name);
for (i = 0; i < iStringLength && i < MAX_NAME_LEN; i++) {
s->name[i] = name[i];
}
}
/* return the SID of student s */
unsigned long getStudentID(const Student* s) { // 's' is a pointer to a Student struct
return s->sid;
}
/* set the SID of student s */
void setStudentID(Student* s, unsigned long sid) { // 's' is a pointer to a Student struct | 'sid' is a 'long' representing the desired SID
s->sid = sid;
}
However, when I try and compile the program, I get a bunch of errors saying that there's an "unknown type name Student". What am I doing wrong?
Thanks!
Move the type definition for Student - the typedef .. right after #define MAX_NAME_LEN 127, i.e. before it's being referenced.
You need to move the declaration of the Student struct above the first time it is referenced by other code - otherwise those functions will not know what it is.
Struct declarations need to be defined before you use them , so you need to move your Student
As cnicutar said, move the typedef - the reason for this is that the type must be known before it's used. Alternatively, you can forward declare the type.
> Move the typedef .. right after #define MAX_NAME_LEN 127, i.e. before
> it's being used.
OR, if you want to keep your definition after, and if you are ready to use a pointer to Student, you can:
#include <stdio.h>
#include <stdlib.h>
#define MAX_NAME_LEN 127
// forward declare Student ici
struct Student;
//...
// in main, use a pointer to student
int main(void) {
Student *sarah; // Changed to pointer
const char* my_name = "Sarah Spond";
setName(sarah, my_name); // Pass the pointer instead of reference
printf("Name is set to %s\n", sarah->name); // Use the pointer
//....
delete sarah; // delete object when done
}
// Change struct decl to the following // can't explain the diff yet
struct Student {
char name[MAX_NAME_LEN + 1];
unsigned long sid;
};
A basic structure of a C program is:
//======DOCUMENT SECTION=========
//File:test.c
//Author:
//Description:
//...
//================================
//====INCLUDE SECTION=============
#include "lib1"
#include <lib2>
//================================
//========DEFINITIONS SECTION=====
#define TRUE 1
#define FALSE 0
//================================
//========STRUCTURES SECTION======
struct P{
};
//================================
//========TYPEDEFS SECTION========
typedef *P P;
//================================
//========FUNCTION HEADERS========
void foo1(...);
int foo2(...,...,...);
//================================
//=========GLOBAL VARIABLES=======
int GLOBAL_INT;
float GLOBAL_FLOAT;
//================================
//=====MAIN FUNCTION DEFINITION===
void main(void)
{
...
...
...
}
//=================================
//======FUNCTIONS DEFINITION======
void foo1(...)
{
}
int foo2(...,...,...)
{
}
//================================
A main function is where a C program starts. A main function also typically has access to the command arguments given to the program when it was executed.
Usually you have got:
int main(void);
int main();
int main(int argc, char **argv);
int main(int argc, char *argv[]);

Resources