Related
I am writing a function that adds items to the shopping list. I understand how to limit the size of the shopping list, but what I want to do is that I want to use dynamic memory allocation by using malloc ().
I want to get rid of the size and store the data as it comes in. Thus if 15 fields of data come in, I want to store 15 and not a specific size. I'm assuming that I don't know how much data is coming into my program.
I am still a beginner, so let me know if I presented the question in a wrong way.
Thank you in advance, I appreciate your opinions.
#define _CRT_SECURE_NO_WARNINGS
#include"ShoppingList.h"
#include<stdio.h>
#include<stdlib.h> // For malloc() and free()
void addItem(struct ShoppingList* list)
{
if (list->length > 4)
{
return 0;
}
printf("Name for product: ");
scanf("%s", list->itemList[list->length].productName);
do
{
printf("Enter the amount: ");
scanf("%f", &list->itemList[list->length].amount);
if (list->itemList[list->length].amount <= 0.0)
{
printf("Input is invalid.\n");
}
} while (list->itemList[list->length].amount <= 0.0);
printf("Enter unit of item: ");
scanf("%s", list->itemList[list->length].unit);
printf("%s was added to the shoppinglist.", list->itemList[list->length].productName);
list->length++;
}
#ifndef SHOPPING_LIST_H
#define SHOPPING_LIST_H
// Struct definitions
struct GroceryItem
{
char productName[20];
float amount;
char unit[10];
};
struct ShoppingList
{
int length;
struct GroceryItem itemList[5];
};
// Function declarations
void addItem(struct ShoppingList *list);
void printList(struct ShoppingList *list);
void editItem(struct ShoppingList *list);
void removeItem(struct ShoppingList *list);
void saveList(struct ShoppingList *list);
void loadList(struct ShoppingList* list);
#endif
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include "ShoppingList.h"
int main(void)
{
struct ShoppingList shoppingList;
shoppingList.length = 0; // The shopping list is empty at the start
int option;
do
{
printf("\n\nWelcome to the shopping list manager!\n");
printf("=====================================\n\n");
printf("1. Add an item\n");
printf("2. Display the shopping list\n");
printf("3. Remove an item\n");
printf("4. Change an item\n");
printf("5. Save list\n");
printf("6. Load list\n");
printf("7. Exit\n");
printf("What do you want to do? ");
scanf("%d", &option);
switch (option)
{
case 1: addItem(&shoppingList); break;
case 2: printList(&shoppingList); break;
case 3: removeItem(&shoppingList); break;
case 4: editItem(&shoppingList); break;
case 5: saveList(&shoppingList); break;
case 6: loadList(&shoppingList); break;
case 7: break;
default:
printf("Please enter a number between 1 and 7");
}
} while (option != 7);
return 0;
}
I would use flexible array members.
typedef struct GroceryItem
{
char productName[20];
float amount;
char unit[10];
}GroceryItem;
typedef struct ShoppingList
{
size_t length;
GroceryItem itemList[];
}ShoppingList;
ShoppingList *additem(ShoppingList *sh, const GroceryItem *item)
{
size_t newsize = sh ? sh -> length + 1 : 1;
sh = realloc(sh, newsize * sizeof(sh -> itemList[0]) + sizeof(*sh));
if(sh)
{
sh -> length = newsize;
sh -> itemList[newsize - 1] = *item;
}
return sh;
}
But personally, I would rather use a linked list instead of an array for this task.
There are several ways to achieve your target:
The first involves no machinery but malloc(3) use, and it is used only when you know in advance (in advance to allocate, but at run time, this is, not when the program is started, but for this usage of the array)
struct the_thing {
/* .... */
};
...
struct the_thing *array_of_things = malloc(number_of_things * sizeof(array_of_things[0]);
This will return a block of memory of size of the product of one element (array_of_things[0] is not a real expression this time, but the argument to the operator sizeof) that calculates the size of the type of the evaluation of the used expression, and doesn't evaluates it ---this is important because you cannot evaluate that expression yet, as the pointer doesn't point yet to the allocated memory--- by the number of elements you are going to use) This converts your pointer (and the pointer arithmetic induced by using the [index] notation) into an usable array (indeed it is a pointer to an array of elements. Important to say that the array is uninitialized and the data contents can be rubish and you have to initialize the elements, one by one, to the desired values. In the case you want an initialized array, you can use, instead, calloc(3) that was defined specifically to allocate arrays of things.
struct the_thing *array_of_things = calloc(number_of_things, sizeof(array_of_things[0]));
look at one detail, we have used a comma this time to specify two quantities as parameters to calloc(), instead of passing the product of both. The result is that calloc(3) returns an initialized array (everything is initialized to zeros) and also, you specify separately the number of elements and the size of one element. This call is specific (but not mandatory specific) to create dynamic arrays. Both calls take as arguments the size of the total block of memory to allocate, and the number of elements and the element size, respectively.
The second way occurs when you need to make the array grow dynamically as you require more and more elements. This can be solved with the previous functions, but there's a function realloc() that does the dirty work for your.
struct the_thing *array_of_things = NULL;
/* now I need n1 elements */
array_of_things = realloc(array_of_things, n1 * sizeof(array_of_things[0]));
with this, array_of_things has passed to hold no element (because it was assigned NULL) to allocate n1 elements. The normal workings allow you to work with this array, until you get to it's limit, now things get more interesting:
/* now I'll need n2 elements (n2 can be larger or smaller than n1 before) */
array_of_things = realloc(array_of_things, n2 * sizeof(array_of_things[0]));
this call (with an already valid pointer) will try to see if the allocation can be solved in place, but if it cannot, a new array will be allocated with enough space to hold n2 elements, the n1 previous elements will be copied into the second array, and the new allocated pointer will be returned, and the previous one will be freed.
This has a possibly complicated drawback, is that you cannot have pointers pointing to element (or element fields) inside the array, because if the new array is repositioned in memory this will make all those pointers invalid (they will still be pointing to the old places, where now nothing exists) But if you can handle that, everything is fine.
I wrote a macro function to handle this situation and it works fine (except when I have pointers pointing inside the array that I have to rearrange all those pointers when I use the macro) The macro requires an array A, with two associated variables, A_len and A_cap (both of type size_t) to be declared with the array:
#define DYNARRAY_GROW(_array _elem_type, _need, _increment) do { \
if (_array##_len + (_need) > _array##_cap) { \
_array##_cap += (_increment); \
_array = (_elem_type *) realloc( \
_array, _array##_cap * sizeof _array[0]); \
} \
} while (0)
that you declare your array as:
struct the_thing *array_of_things;
size_t array_of_things_len = 0;
size_t array_of_things_cap = 0;
and then, you use it:
/* I need n1 elements */
DYNARRAY_GROW(array_of_things, /* the array */
struct the_thing, /* the type of element (see note below) */
1, /* only one element more needed */
10); /* in case of grow, 10 elements are to be added */
In which the parameters
array_of_things is the array name. See from the macro definition that the _cap suffixed variable and the _len suffixed variables are derived from the name used here, so names are tied together (this makes less error prone the code)
struct the_thing is the type of an array element. You will see that it is used only to cast the returned pointer from realloc() to the proper type (thing that normally is discouraged in C, but for environments in which C code is tested using C++ testing code ---like GTest/GMock--- this is required, to avoid the resulting error from the C++ compiler) So while this cast is not only unnecessary in C (and even dangerous to use) it is forbidden in C++, and to allow compatibility with C++ (and being part of a tested macro) has been provided for convenience.
1 is the amount of required elements. It is supposed that you call this macro to add some number of elements (normally one) to it, one shot, this is the amount of such elements you are going to add.
10 is the amount of elements to grow in case a grow is required. Despite the number of elements to grow you need, it is often far more efficient to allocate a bigger ammount so not every time we need one element we allocate only one, but a bunch of them, so the number of total calls to realloc() is decreased, adding efficiency to the overal code.
In your case, for example:
struct ShoppingList *
shopping_list = NULL;
size_t shopping_list_cap = 0,
shopping_list_len = 0;
void addItem(
struct ShoppingList *element)
{
DYNARRAY_GROW(shopping_list,
struct ShoppingList,
1, /* what is needed */
10); /* what we get in that case. */
/* after that we're able to add it (we have one
* free slot at least to add an element) */
shopping_list[shopping_list_len++] = *element; /* copy the data */
}
Of course, when you are done with the shopping list, you need to set all three global variables to NULL, 0 and 0.
free(shopping_list);
shopping_list = NULL;
shopping_list_len = shopping_list_cap = 0;
Note: I have deliberately not done error checking, because is not clear in your homework how it is to be handled the occasional (and rare) case that you get NULL from realloc(). This case is a bit cumbersome because it requires you to make a second copy of the pointer before calling realloc() (as the value stored in shopping_list will be destroyed by the assignment of NULL to the pointer variable, in case the realloc() fails)
Normally, a memory allocation fail means you have some memory leak somewhere, as:
systems have today enough virtual memory allocatable for each process (this means amount of physical memory plus swap space), so it is improbable that you allocate the total amount of memory of your machine in a single process.
In case you need to be limited the amount of data memory for your process, it is assumed you know how to deal with memory allocation errors to write a working solution for that case, just make a copy of the pointer, run the above code and if you got a NULL return value, then continue (if you still call) without the allocation (e.g. try a lower increment, wait some time so we have more memory, etc.) by recovering the copy into the array pointer.
If you run in an embedded system with small memory, it is many times undesired to dynamically allocate the memory because there's almost no heap space to do dynamic memory allocation. Then you have to preassign static arrays and run this way.
Edit: solved by kaylums little comment. Thank you!
good morning,
I am relatively new to C still and I'm trying to make a doubly linked list.
I got my program to run properly with all the functions with this kind of element:
the program crashes after either 2 or 3 inserted elements in the list in the calloc() call of my insertElement() function. I don't get any SIGSEGV or anything, the program just stops with a random negative return.
I'll try to give a minimum code example of the function and the function call:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct Element {
char name[30];
}Element;
typedef struct List {
int size;
Element* first;
Element* last;
}List;
Element* insertElement(List* List, char name[30]) {
Element* element;
element = (Element*)calloc(0, sizeof(Element));
strncpy_s(element->name, name, 30);
return element;
}
List globalList;
char name[30];
int main() {
while (true) {
printf("insert the name >>");
if (fgets(name, 30, stdin) != NULL)
name[strcspn(name, "\n")] = 0;
insertElement(&globalList, name);
}
}
is there already something obvious wrong with that basic stuff?
Thank you very much in advance! Any advice would be very much appreciated, have a good day!
element = (Element*)calloc(0, sizeof(Element));
what is 0 in first argument?
actually you ask for 0 number of your type from memory!
here is some explanation about dynamic memory allocation:
Dynamic memory allocation is a process of allocating memory at run time. There are four library routines, calloc(), free(), realloc(), and malloc() which can be used to allocate memory and free it up during the program execution. These routines are defined in the header file called stdlib.h.
What is malloc() ?
It is a function which is used to allocate a block of memory dynamically. It reserves memory space of specified size and returns the null pointer pointing to the memory location.
The pointer returned is usually of type void. It means that we can assign malloc function to any pointer. The full form of malloc is memory allocation.
What is calloc() ?
Calloc() function is used to allocate multiple blocks of memory. It is a dynamic memory allocation function which is used to allocate the memory to complex data structures such as arrays and structures. If this function fails to allocate enough space as specified, it returns will null pointer. The full form of calloc function is contiguous allocation.
Why use malloc() ?
Here are the reasons of using malloc()
You should use malloc() when you have to allocate memory at runtime.
You should use malloc when you have to allocate objects which must exist beyond the execution of the current memory block.
Go for malloc() if you need to allocate memory greater than the size of that stack.
It returns the pointer to the first byte of allocated space.
It enables developers to allocate memory as it is needed in the exact amount.
This function allocates a memory block size of bytes from the heap.
Why use calloc() ?
Here are the reasons of using calloc()
When you have to set allocated memory to zero.
You can use calloc that returns a pointer to get access to memory heap.
Used when you need to initialize the elements to zero to returns a pointer to the memory.
To prevent overflow that is possible with malloc()
Use calloc() to request a page that is known to already be zeroed.
Syntax of malloc()
Here is a Syntax of malloc()
ptr = (cast_type *) malloc (byte_size);
n above syntax, ptr is a pointer of cast_type. The malloc function returns a pointer to the allocated memory of byte_size.
Example of malloc() in C
In the bellow code, sizeof(*ptr) is used to allocate a memory block of 15 integers. In the printf statement, we are finding the value of the 6th integer.
#include<stdlib.h>
#include<stdio.h>
int main(){
int *ptr;
ptr = malloc(15 * sizeof(*ptr));
if (ptr != NULL) {
*(ptr + 5) = 480;
printf("Value of the 6th integer is %d",*(ptr + 5));
}
}
Output:
Value of the 6th integer is 480
Syntax of calloc()
Here is a Syntax of malloc()
ptr = (cast_type *) calloc (n, size);
The above syntax is used to allocate n memory blocks of the same size. After the memory space is allocated, all the bytes are initialized to zero. The pointer, which is currently at the first byte of the allocated memory space, is returned.
Example of calloc() in C
The C language program below calculates the sum of the first ten terms. If the pointer value if null, then the memory space will not be allocated.
For loop is used to iterate the value of a variable "i" and print the sum. Lastly, function free is used to free-up the pointer.
#include <stdio.h>
#include <stdlib.h>
int main() {
int i, * ptr, sum = 0;
ptr = calloc(10, sizeof(int));
if (ptr == NULL) {
printf("Error! memory not allocated.");
exit(0);
}
printf("Building and calculating the sequence sum of the first 10 terms \n");
for (i = 0; i < 10; ++i) { * (ptr + i) = i;
sum += * (ptr + i);
}
printf("Sum = %d", sum);
free(ptr);
return 0;
}
Output:
Building and calculating the sequence sum of the first 10 terms n Sum = 45
I will not extend on the actual problem (specifying 0 as the number of elements requested to calloc()). I will point you to several other things found in your code.
The first problem in reading your code is that you lack to include the file <stdbool.h>, necessary to use the constants true and false and the type bool. I have added it in the first line.
#include <stdbool.h>
Next, you use at several places the value 30 as the size of several objects that are all related. If you decide in the future to change that value, it will be difficult to find all the ocurrences of the constan 30 and change all of them (and the risk you have used also 30 for anything else and it gets changed in the middle)
I have included a constan with the following lines:
#define NAME_LENGTH (30)
and all the definitions:
...
char name[NAME_LENGTH];
in the structure...
Element* insertElement(List* List, char name[NAME_LENGTH]) {
in the prototype of insertElement (you don't need as name is actually defined as char *, not as an array of NAME_LENGTH elements...
On other side, you need to include a pointer on each Element to link each to the next element of the list. This is done right after name:
struct Element *next; /* we need to include struct as the type Element is not yet defined */
Next, include sizeof *element as the second parameter to calloc() and 1 to the first. Better, if you are going to initialize all fields in the Element structure, then it is better to call malloc() (see the final code , posted at the end)
NEVER, NEVER, NEVER cast the value returned by malloc()
(and friends) This is a legacy that causes a lot of
errors, that get undetected (and very difficult to find),
due to the cast. When you cast you tell the compiler:
leave it in my hands, as I know what I'm doing. And this
makes the compiler silent, when it should be complaining.
The problem mainly has to do with forgetting to include
the header file where malloc (and friends) are declared
(<stdlib.h>) and you will take long time to detect and
see why your program has crashed.
For the same reason, don't use the size of the type, when
you can use the pointed to expression as template of the
type. This is because if you change the type of the
pointed to object, you need to remember that here you have
put the type of the object (and you need to change it too)
This way, this expression
will only be bad if you change the object into a non
pointer object. Also, you have requested for 0 elements
of the specified type, which has already been noticed in other answers. This will make calloc() to return NULL, value you don't check in your code, and you try to use it later on. This will crash your program, but in the best case, it is Undefined Behaviour (and a very difficult error to find, so be careful and always check the value returned by malloc()).
Next, don't use strncpy_s() as it is Microsoft specific routine, and isn't included in any standard. A proper substitute has been provided by strncpy():
strncpy(element->name, name, sizeof element->name);
also use the sizeof operator, as it protects you if you decide in the future to change the type of the pointer.
Finally, it is better to use fgets() as the test expression for the while statement in main(). The reason is that you can end the loop when the end of file is detected.
Finally, you code ends as (including the linking of Elements in the linked list):
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define NAME_LENGTH (30)
typedef struct Element {
char name[NAME_LENGTH];
struct Element *next;
} Element;
typedef struct List {
int size;
Element* first;
Element* last;
} List;
Element* insertElement(List* List, char name[NAME_LENGTH]) {
Element* element;
/* NEVER, NEVER, NEVER cast the value returned by malloc
* (and friends) This is a legacy that causes a lot of
* errors, that get undetected (and very difficult to find),
* due to the cast. When you cast you tell the compiler:
* leave it in my hands, as I know what I'm doing. And this
* makes the compiler silent, when it should be complaining.
* The problem mainly has to do with forgetting to include
* the header file where malloc (and friends) are declared
* (<stdlib.h>) and you will take long time to detect and
* see why your program has crashed. */
/* for the same reason, don't use the size of the type, when
* you can use the pointed to expression as template of the
* type. This is because if you change the type of the
* pointed to object, you need to remember that here you have
* put the type of the object. This way, this expression
* will only be bad if you change the object into a non
* pointer object. Also, you have requested for 0 elements
* of the specified type. */
element = malloc(sizeof *element);
/* don't use strncpy_s as it is not standard. Use the sizeof
* operator again, to protect the expression if you change
* the type of element->name */
strncpy(element->name, name, sizeof element->name);
element->next = NULL;
if (List->last) {
List->last->next = element;
List->last = element;
} else {
List->first = List->last = element;
}
return element;
}
List globalList;
char name[NAME_LENGTH];
int main() {
/* if you put the fgets() call as the test of the while
* statement below, you will process each line until you get
* an end of file condition. Then you can do both things: to
* null the occurence of the \n char, and the call to
* insertElement() I have not corrected because it's a
* question of taste. */
printf("insert the name >> ");
while (fgets(name, sizeof name, stdin) != NULL) {
/* sizeof name is better than the constant, as if you
* change the type definition of object name, you have to
* remember that you are using here its size. sizeof
* does the job for you. */
name[strcspn(name, "\n")] = 0;
insertElement(&globalList, name);
printf("insert the name >> ");
}
Element *p;
char *sep = "\n\n{ ";
for (p = globalList.first; p; p = p->next) {
printf("%s\"%s\"", sep, p->name);
sep = ", ";
}
printf(" };\n");
}
how is it possible to take the #define value from the user input instead of pre-defining it in a code when structures are involved.Given the code below, I would like to take the value N from the user, is it possible or should I try something else
#define N 4
// Data structure to store graph
struct Graph {
// An array of pointers to Node to represent adjacency list
struct Node* head[N];
};
This is not possible in the way you are trying to do. You cannot dynamically (run-time) redefine a type in C.
One alternative could be to store a double pointer and allocate memory according to what the user asks.
Change the Graph struct to the following:
// Data structure to store graph
struct Graph {
// A double pointer to Node to represent adjacency list
struct Node** head;
};
Now, depending on the value N, you could dynamically allocate the memory required.
int N = 4;
Graph g;
g.head = malloc(sizeof(struct Node*) * N);
Here, N can equally well be a #define or a variable set at run-time. The rest of your code could remain the same. You can continue to use g.head[i] to refer to the i'th element, just like you would if you had an array.
Of course, don't forget to free() the allocated memory when you are done or you will have a leak!
It is impossible at runtime. #define macros are replaced and determined at compilation time, so predetermined at runtime. You would have to receive the user input into a variable, and dynamically allocate your head array.
However as was implied in one of the comments. You can use the -D flag at compilation time to set a value to the macro. So you could create a script that takes a value from the user and run something like:
gcc -DN=$userinput ...
It's not possible. However, the compiler provides preprocessor controlling options. For e.g. gcc compiler has an option -D:
-D name=definition
The contents of definition are tokenized and processed as if they appeared during translation phase three in a '#define' directive....
For e.g. consider this code
#include <stdio.h>
int main(void) {
#ifdef N
printf ("N: %d\n", N);
#endif
return 0;
}
Compiling this code:
#gcc -DN=10 -Wall -Wextra pp.c
the -DN=10 is equivalent to #define N 10
Run:
#./a.out
N: 10
You'll have to read more about dynamic allocation, for example from here:
https://www.cs.swarthmore.edu/~newhall/unixhelp/C_arrays.html
As a small example taken from the above link:
// declare a pointer variable to point to allocated heap space
int *p_array;
// call malloc to allocate that appropriate number of bytes for the array
p_array = (int *)malloc(sizeof(int)*50); // allocate 50 ints
// always CHECK RETURN VALUE of functions and HANDLE ERROR return values
// here is one example of handling an unrecoverable malloc error
// (other error handling code is removed from this document for readability):
if(p_array == NULL) {
printf("malloc of size %d failed!\n", 50); // could also call perror here
exit(1); // or return an error to caller
}
// use [] notation to access array buckets
// (THIS IS THE PREFERED WAY TO DO IT)
for(i=0; i < 50; i++) {
p_array[i] = 0;
}
Also read the malloc docs:
https://en.cppreference.com/w/c/memory/malloc
i try to store name and age in a dynamic array
when we have a different type of data , int , and Char that we dont know the size in the start how to use a dynamic array to store the 2 types
typedef struct personne{
char nom ;
int age ;
}personne;
struct personne saisie_personne_suivante(struct personne* x){
scanf("%s",&x->nom);
scanf("%d",&x->age);
return *x;
}
int main(void){
personne *ali;
ali = malloc(sizeof(char*));
saisie_personne_suivante(ali);
printf("\n %d ",ali->age);
printf("\n %s",&ali->nom);
return 0;
}
Why i dont sucess ?
i think we cant store two types of data at a time in array.If we do so we need to allocate half of memory to char and half to integers provided you should give some size of array.
=>in your program at this line [ali = malloc(sizeof(char*))] you are passsing address of only char not of variable.If you want to store both values just pass address of both int and char.
ali is a pointer to a struct of size sizeof(char) + sizeof(int) which may vary between architectures.
For the time being, let's assume it's 5 bytes (which it probably is on your PC).
What you're doing, is allocate space equal to size of a pointer to char, (which is either 32 or 64bits wide, depending on your OS).
What you probably want to do is allocate space equal to size of your struct (5 bytes), that is:
ali = malloc(sizeof(personne));
Note the lack of *, since you want actual memory for a struct and not a pointer pointing to such a location.
By the way, you wouldn't want to write: malloc(sizeof(char)) either, since that would be just one byte needed for your struct.
I strongly advise you to get your hands on a book on C or a decent tutorial at least.
int main() {
personne *ali;
ali = (struct personne *)malloc(sizeof(personne));
saisie_personne_suivante(ali);
printf("\n %d ", ali->age);
printf("\n %c", ali->nom);
return 0;
}
There is not enough memory for struct personne, so you need to malloc sizeof(personne) memory. nom is not a pointer,it's a char variable,when you print it, use printf("%c",ali->nom);
I can concur with the commenters who recommended a good book/tutorial to get started but nevertheless: here is your repaired code, with a bit of comment.
// printf(), fprintf(), and puts()
#include <stdio.h>
// exit(), malloc(), and scanf()
#include <stdlib.h>
#define PERSONNE_ERROR 0
#define PERSONNE_OK 1
typedef struct personne {
// fixed width for 49 characters and the trailing NUL
char nom[50];
int age;
} personne;
int saisie_personne_suivante(struct personne *x)
{
// For the returns of the scanf()s.
// Because you always check the returns if available
// (well, actually: the returns of printf() et al. rarely get checked)
// preset it to a value meant to say "OK"
int res = PERSONNE_OK;
// UX: let the users know what they are supposed to do.
puts("Your name, please");
// we have a fixed maximum size of name and we can set it here within scanf()
// scanf() returns the number of elements it parsed, *not* the number of characters
// sacnf() needs a pointer to the memory it is expected to put the value into.
// x->nom is already a pointer to a char array, no need to use "&"
if ((res = scanf("%49s", x->nom)) != 1) {
// we can return immediatly here.
// If we would need to cleanup (free memory, for example) we would
// set res to PERSONNE_ERROR and use a goto to jump at the place
// where all the cleanup happens. But that should be done if the clean-up
// is always the same (or could be sorted) and you need such cleanups
// more than just two or three times.
return PERSONNE_ERROR;
}
puts("Your age, too, if you don't mind.");
// x->age is not a pointer to an int, hence we need to prefix "&"
if ((res = scanf("%d", &x->age)) != 1) {
return PERSONNE_ERROR;
}
return res;
}
int main(void)
{
personne *ali;
int res;
// reserve momory for the struct
ali = malloc(sizeof(personne));
// call function that fills the struct and check the return
if ((res = saisie_personne_suivante(ali)) != PERSONNE_OK) {
fprintf(stderr, "Something went wrong with saisie_personne_suivante()\n");
exit(EXIT_FAILURE);
}
// print the content of struct personne
// you can feed printf() directly, no need to find the pointer to the memory
// holding the int
printf("Age: %d\n", ali->age);
// To print strings it needs to know the start of the string whcih needs to be
// a pointer and ali->nom is a pointer to the start of the string
printf("Name: %s\n", ali->nom);
// free allocated memory (not really necessary at the end of the
// program but it's deemed good style and because it costs us nothing
// we cannot find a good reason to skip it)
free(ali);
// exit with a value that tells the OS that this programm ended without an error
// It shoudl be 0 (zero) which it almost always is.
// *Almost* always
exit(EXIT_SUCCESS);
}
But really: go and get some beginners book/tutorial. I cannot give you a recommendation because I don't know about any good ones in your native language (sometimes the english version is good but the translation lacks a lot).
Is there anyway to write the code without having to initialise the size of the array?
#include <stdio.h>
#define MAXSIZE 100
int main()
{
int i,n;
int num[MAXSIZE];
printf("Enter the value of n\n");
scanf("%d",&n);
printf("Enter the list of integers\n");
for(i=0;i<n;i++);
scanf("%d",&num[i]);
for(i=0;i<n;i++)
printf("%d\t",num[i]);
return 0;
}
I used MAXSIZE since the compiler required me to initialise the size, an error came up everytime I left the size blank. All this because incase the user wants to input more than 100 values, how do i accomodate him?
Is using pointers a better way to write the program?
I tried by changing
#include<stdio.h>
int main()
{
int *num,n,i;
printf("Enter the value of n\n");
scanf("%d",&n);
printf("Enter the list of integers\n");
for(i=0;i<n;i++);
scanf("%d",num+i);
for(i=0;i<n;i++)
printf("%d\t",*(num+i));
return 0;
}
This is giving me a warning saying uninitialised local variable in visual studio and isn't inputting all the numbers. Output is garbage values.
Dev c++ crashes everytime I execute.
Any advice would be helpful, Thanks in advance guys.
If you are using a compiler that supports variable-length arrays (C99 or later, although VLAs are now optional under C2011) and the size of the array is relatively small, you can do the following:
int i, n;
...
scanf( "%d", &n );
int num[n];
// load and print num as before
If your compiler does not support VLAs or the array size is large (more than a few hundred K), then you will want to allocate memory dynamically using either malloc or calloc:
int i, n;
...
scanf( "%d", &n );
int *num = malloc( n * sizeof *num );
// load and print num as before
When you use just a plain pointer, you still need to allocate memory for the array. We can do that with malloc!
int *num,n,i;
printf("Enter the value of n\n");
scanf("%d",&n);
num = malloc(sizeof(*num) * n);
printf("Enter the list of integers\n");
...
Also, even though you are using pointers, you can still write num[i] instead of *(num +i). In fact, those two expressions are always interchangeable, and so you you should use the one that makes your code the most readable.
You can use variable length arrays if you want user to put the size of array (run program in C99 ode. Use the option: -std=c99).
Arrays are used when you need small memory. If you need some large amount of memory then go with pointers and dynamic allocation. When using pointer, initialize it to some memory location before any access to it.
Arrays are NOT pointers !
Their types types are completely different and are treated differently by the compiler.
int *num ;
declares num as pointer to int, which is not pointing to any valid memory address
("uninitialized" as reported by compiler ) . Whatever operation you're doing in second case invokes undefined behaviour
You need to point it to a valid memory location, in this case by using malloc call
num = malloc( sizeof( int ) * n);