How to use a pointer in a structure - c

If you enter 1 for the first id, 2 for the password, 3 for the second, 4 for the password, 5 for the last destination, and 6 for the d, the results are all displayed as 5 and 6.
I'd appreciate your help.
I wonder that the output values are all 5 and 6.
( You must write a pointer inside the structure. )
void game(struct gameInfo *login, char *id, char *password) {
printf("game dts: ");
fgets(id, sizeof id, stdin);
login->dts = id;
cl(login->dts);
printf("game password: ");
fgets(password, sizeof password, stdin);
login->password = password;
cl(login->password);
}
void printGame(struct gameInfo *login) {
for (int i = 1; i < 4; i++) {
printf("%d %35s %35s\n", i, (login + i)->dts, (login + i)->password);
login++;
}
}
int main(void) {
for (int i = 1; i < 4; i++) {
gameInfo(login + i, id, password);
printf("(login + i)-> dst, (login + i)->password);
login++;
}
}

A pointer points to another variable. All your FlightInfos' dates point to the dateStr variable in main, and all their destinations point to the destinationStr variable in main. So when you print what they point to, you're printing the dateStr and destinationStr variables in main.
To solve it you would have to create new "variables" to hold each FlightInfo's date and destination. The obvious way to do it would be to make them arrays instead of pointers, but I guess the purpose of the exercise is to learn pointers - you can use malloc to allocate some memory space for long-term usage, and then access it by pointer. (Don't try to store the date and destination in local variable arrays inside fillFlightInfo, since you'll get a similar problem - when it returns, the local variables are deleted and the space will be reused for the next call)

Related

Can't write text in a text file using loop

I am trying to write text to a file using loops, but when I make it like (ogrenci+i) using i and not like (ogrenci+0) I'm getting some weird numbers and text in txt file.
When writing like this (ogrenci+0) it works correctly. What am I doing wrong?
I attent pointer to struct in a different function.
this is the question
QUESTIONS
Assume that you are given the structure below
typedef struct StudentMark {
char name[20];
char surname[20];
int midterm;
int final;
}STUDENT_MARK;
1-) Write down a program which contains
a-) A function to get the user entered name, surname, and exam marks into
dynamically
allocated STUDENT_MARK structure (your function MUST check input validity
i.e
entered marks must between [0..100]).
b-) A function to write down the entered VALID structures into a file
named as
marks_YOUR_STUDENT_ID.txt.
2-) Write a program which contains
a-) A function to read a file named as marks_YOUR_STUDENT_ID.txt which contains
STUDENT_MARK structures’ data.
b-) A function to calculate the average of each student’s exam marks and writes the result
onto screen as
“The student NAME SURNAME’s midterm mark is MIDTERM, final mark is
FINAL and his/her average is AVERAGE”
void girme (int studentnum){
int i;
studentnum = 2;
STUDENT_MARK *ogrenci;
ogrenci = (STUDENT_MARK*) malloc(studentnum * sizeof(STUDENT_MARK));
if(ogrenci == NULL) { exit(1); }
for(i=0;i<studentnum;i++)
{
printf("Enter the student's name, surname, midterm and final respectively: \n");
scanf("%s %s %d %d",(ogrenci+i)->name, (ogrenci+i)->surname, &(ogrenci+i)->midterm, &(ogrenci+i)->final);
if((ogrenci+i)->midterm > 100 || (ogrenci+i)->midterm < 0 || (ogrenci+i)->final > 100 || (ogrenci+i)->final < 0)
{
printf("midterm or final can not be higher than 100 or lower than 0 \n");
exit(1);
}
}
}
void yazma (int studentnum){
int i;
STUDENT_MARK *ogrenci;
FILE *dosya;
dosya = fopen("marks_190704033.txt","w");
if{ (dosya == NULL)
{
printf("Could not open file");
exit(1);
}
else
{
for(i=0;i<studentnum;i++)
{
fprintf(dosya, "%s %s %d %d", (ogrenci+0)->name, (ogrenci+0)-
>surname, (ogrenci+0)->midterm, (ogrenci+0)->final);
}
}
fclose(dosya);
}
int main()
{
int n =2;
girme(n);
yazma(n);
return 0;
}
STUDENT_MARK *ogrenci;
ogrenci = (STUDENT_MARK*) malloc(studentnum * sizeof(STUDENT_MARK));
ogrenci is a single pointer to the structure STUDENT_MARK to space allocated for several objects of struct STUDENT_MARK.
When using, f.e.:
(ogrenci+i)->name
in the for loop, you attempt to access not existing struct pointers to not existing structure objects.
Note: The compiler do not associate the allocated space with several pointers!
If you want to use pointer arithmetics like (ogrenci + i) you need to either define ogrenci as an array of pointers to STUDENT_MARK:
int studentnum = 5;
STUDENT_MARK *ogrenci[studentnum];
and initialize each pointer by the address of an existing structure object for which were each allocated space individually, f.e. like:
int studentnum = 5;
STUDENT_MARK *ogrenci[studentnum];
for(int i = 0; i < studentnum; i++)
{
ogrenci[i] = malloc(sizeof(*ogrenci));
}
or you define ogrenci as a pointer to pointer to STUDENT_MARK:
int studentnum = 5;
STUDENT_MARK **ogrenci;
ogrenci = malloc(sizeof(*ogrenci) * studentnum);
*ogrenci = malloc(sizeof(**ogrenci) * studentnum);
"When writing like this (ogrenci+0) it works correctly."
However, It "works" with 0 because ogrenci + 0 = ogrenci. There is no difference to ogrenci.
Side note: As you mabe have already seen, I omitted the cast of the returned pointer from malloc. This is because it is unnecessary and it might "add clutter" to your code: Do I cast the result of malloc

c - dynamically allocate variable names

I am trying to take number of inputs from a user and take the inputs then and store them under dynamically created variable names. can anyone help?
I want to take the number of array user want to input then create the exact number of variables which maintains a common pattern so I can know which array is under which variable and I can call them for further processing.
My current code is as follows
int input, eqn, m, i,n,x;
char inputarr[100], eqnarr[100];
printf("Enter number of variables: ");
scanf("%d",&n);
m=n;
printf("Enter your variables: \n");
while(n!=-1){
gets(inputarr[n]);
n--;
}
while(m!=0){
puts(inputarr[m]);
printf("\n");
m--;
}
my inputs are like
2 (here 2 is number of inputs user intended to give)
a = 3
b = 4
I need to save them in 2 variables say var1 and var2 as I need to work with them later.
C does not support dynamically created variables. You can instantiate dynamic objects through calls to malloc(), but these will not be named. In C, names are just labels used to associate names to memory locations at compile time, and resolved at link time. It is way too late at run time.
You can create a mapping from names to int values, but you cannot create new variables. A Mapping will work for you. You need to create a method to add a named value to your mapping, a method to retrieve the value, a method to update its value, and for completeness, you need a fourth method to delete an element when you no longer need it.
Here is a simple example of mapping variable names to int values using a dynamic lookup table. To be complete, you would need to add methods for updating values, and deleting them, etc.
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#define MAX_VARIABLES 100
typedef struct Lookup_Entry_Struct {
char* Name;
int Value;
} LookUp_Entry;
typedef struct Mapping_Struct {
int MaxEntries;
int NumEntries;
LookUp_Entry* mapping;
} Mapping;
void initMapping(Mapping* map, int MaxEntries)
{
map->NumEntries = 0;
map->MaxEntries = MaxEntries;
map->mapping = calloc(sizeof(LookUp_Entry), MaxEntries);
if (map->mapping == NULL) {
// Failed to allocate the Mapping table
fprintf(stderr, "Failed to alloc Mapping table of %d entries\n", MaxEntries);
map->MaxEntries = 0;
}
}
bool addMap(Mapping* map, char* Name, int Val)
{
bool Added = false;
if (map->NumEntries < map->MaxEntries) {
// There is still room in the table, add this new variable
LookUp_Entry* newEntry = &(map->mapping[map->NumEntries]);
newEntry->Value = Val;
newEntry->Name = malloc(strlen(Name)+1);
strcpy(newEntry->Name, Name);
map->NumEntries++;
Added = true;
}
return Added;
}
int lookup(Mapping* map, char* Name)
{
int val = -1;
int i = 0;
bool Found = false;
// Search the map to see if we can find Name
for(i=0; i < map->NumEntries && !Found; i++)
{
LookUp_Entry* entry = &(map->mapping[i]);
if (strcmp(entry->Name, Name) == 0) {
// Found a match, return the value in *Val
val = entry->Value;
Found = true;
}
}
if (!Found)
fprintf(stderr, "lookup of \"%s\" not found in map\n", Name);
// Found value, or -1 if not found
return val;
}
void getVariablesFromUser(Mapping* map)
{
#define MAXNAMELEN 100
// Code modified from Buno's sample
int NumVariables = 0;
int i;
char inputName[100];
int inputVal;
while ((NumVariables<1) || (NumVariables > MAX_VARIABLES)) {
printf("Enter number of variables: ");
scanf("%d", &NumVariables);
if (NumVariables<0 || NumVariables>MAX_VARIABLES)
fprintf(stderr, "Please enter no more than %d variables!\n", MAX_VARIABLES);
}
printf("Init mapping for %d variables\n", NumVariables);
initMapping(map, NumVariables);
for(i=0; i<NumVariables; i++) {
printf("Enter variable #%d name and initial value: ", i+1);
scanf("%s %d", &(inputName[0]), &inputVal);
printf("Adding variable %s with initial value %d\n", inputName, inputVal);
addMap(map, inputName, inputVal);
}
}
int main(int argc, char** argv)
{
Mapping myVarMap;
char* varName;
int i;
getVariablesFromUser(&myVarMap);
// Display all the variables to show how to retrieve values
printf("%d variables added by user\n", myVarMap.NumEntries);
for(i=0; i<myVarMap.NumEntries; i++) {
LookUp_Entry *entry = &(myVarMap.mapping[i]);
char* name = entry->Name;
printf("Entry #%d: %s = %d\n", i+1, name, lookup(&myVarMap,name));
}
}
Save this in file lookup.c, then to compile it:
gcc lookup.c -o lookup
Here is sample run:
scott> lookup
Enter number of variables: 3
Init mapping for 3 variables
Enter variable #1 name and initial value: Bob 123
Adding variable Bob with initial value 123
Enter variable #2 name and initial value: Ted 999
Adding variable Ted with initial value 999
Enter variable #3 name and initial value: Sally 0
Adding variable Sally with initial value 0
3 variables added by user
Entry #1: Bob = 123
Entry #2: Ted = 999
Entry #3: Sally = 0
scott>
You cannot create variable names dynamically, however you can dynamically allocate memory using a function called 'malloc()'. You need to first understand pointers and then learn how to create and access memory during run-time.
As mentioned in the comments and answers of others, you cannot dynamically create variables in C.
However, you can follow this approach:
Dynamically read the characters for each line of n expressions (When the
length of input string is not fixed) For ex, Consider n =1 and the
input line is "a=10" Read each character 'a', '=' , '1' , '0'
Parse the string "a=10" to obtain the value 10. Dynamically allocate
memory to store this value 10.
Do this for all n input lines.
Here is the code to achieve this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Dynamically read the input string character by character: Taken from a SO answer
char *inputString(FILE* fp, size_t size){
//The size is extended by the input with the value of the provisional
char *str;
int ch;
size_t len = 0;
str = realloc(NULL, sizeof(char)*size);//size is start size
if(!str)return str;
while(EOF!=(ch=fgetc(fp)) && ch != '\n'){
str[len++]=ch;
if(len==size){
str = realloc(str, sizeof(char)*(size+=16));
if(!str)return str;
}
}
str[len++]='\0';
return realloc(str, sizeof(char)*len);
}
int main(void) {
int n,i,numindex;
char *variableline,*vartemp;
char keys[] = "1234567890";
//Read in the number of variables
printf("Enter n\n");
scanf("%d\n",&n);
printf("Enter %d lines\n",n);
//Allocate memory for these variables
int *variable_values = malloc(n*sizeof(int));
for(i=0;i<n;i++){
// Read the characters dynamically from the n input lines
variableline = inputString(stdin, 10);
//numindex - index where the number starts. For ex, in the string "a=12", numindex is the position of '1'
numindex = strcspn (variableline,keys);
//Read the number into vartemp
vartemp = malloc(strlen(variableline));
strncpy(vartemp, variableline+numindex, strlen(variableline) - numindex);
//Convert the string to number
*(variable_values+i) = atoi(vartemp);
}
printf("The variable values are:\n");
// All the variable values are stored in the dynamically created memory variable_values
for(i=0;i<n;i++)
printf("%d\n",variable_values[i]);
return 0;
}

Clear char array in C without any standard library

I'm working on a class project that would require me to make unique strings and I want to concatenate a number to a string. However I do NOT have access to C Standard Library (memset, malloc, etc.). I made this which works:
char* concat(char* name, int num) {
int i, j;
char newName[50], stack[5];
for(i=0; name[i]!='\0'; ++i) {
newName[i] = name[i];
}
for (j=0; num>=1 || num==0; j++) {
stack[j] = (num % 10) + '0';
num = num / 10;
if (num==0) break;
}
while (j>=0) {
newName[i++] = stack[j--];
}
name[0] = '\0';
return newName;
}
But then as I tested it with multiple strings, I realized that newName was being reused over and over. For ex.
This test file outputs the following:
int main() {
char* rebecca = concat("rebecca", 1);
char* bill = concat("bill", 2);
Write(rebecca); /* bill2ca1 */
Write(bill); /* bill2ca1 */
}
It successfully appends the 1 to rebecca, but then when I call concat on bill, it overwrites the first 5 letter but keeps the same chars from before in newName.
QUESTION: How to clear a char array so the next time it's called it will be set to empty, or dynamically allocate it (without using C Standard Library)?
Without using malloc, you can simply put the memory on the stack of the calling function, to keep in the scope where it is needed. It's easier to add the buffer pointer to the argument list like so:
char* concat(char *newName, char* name, int num) {
int i, j;
char stack[5];
:
:
}
int main() {
char rebecca[50];
char bill[50];
concat(rebecca, "rebecca", 1);
concat(bill, "bill", 2);
write(rebecca);
write(bill);
}
Generally speaking, assign memory where it will be used. Embedded programming (which might need to run for months without a reboot) avoids malloc like the plague, just because of the risk of memory leaks. You then need to assign extra space since you may not know the size at compile time, and then ideally check for running past the end of the buffer. Here we know the string sizes and 50 chars is more than enough.
Edit:
The other issue is that you're not null terminating. The print will go until it hits 0x00. Your line
name[0] = '\0';
should be
newName[i] = '\0';
You've got a major issue that you're overlooking. In your function, newName is a local variable (array) and you're returning it from the function. This invokes undefined behavior. The beauty of UB is that, sometime it appears to work as expected.
You need to take a pointer and allocate memory dynamically instead, if you want to return it from your concat() function. Also, in the main(), after using it, you need to free() it.
A better alternative, maybe, if you choose to do so, is
Define the array in the caller.
Pass the array to the function.
Inside the function, memset() the array before you perform any other operation.
One thing to remember, this way, every call to the function will clean the previous result.
EDIT:
If you cannot use memset(), in the main, you can use a for loop like
for (i = 0; i < sizeof(arr)/sizeof(arr[0]); i++)
arr[i] = 0;
to clear the array before passing it on next time.
You're returning the address of a local variable. Since the variable goes out of scope when the function returns, this invokes undefined behavior.
You function should dynamically allocate memory for the result of the concatenation, then return that buffer. You'll need to be sure to free that buffer later to prevent a memory leak:
char* concat(char* name, int num) {
int i, j;
char *newName, stack[5];
// allocate enough space for the existing string and digits for a 64-bit number
newName = malloc(strlen(name) + 30);
for(i=0; name[i]!='\0'; ++i) {
newName[i] = name[i];
}
for (j=0; num>=1 || num==0; j++) {
stack[j] = (num % 10) + '0';
num = num / 10;
if (num==0) break;
}
while (j>=0) {
newName[i++] = stack[j--];
}
newName[i] = '\0';
return newName;
}
int main() {
char* rebecca = concat("rebecca", 1);
char* bill = concat("bill", 2);
Write(rebecca);
Write(bill);
free(rebecca);
free(bill);
}

Add a new record using pointer and realloc

Hey Guys so basically I'm writing a program where you prompt the user how many first names he wants to store. You then create the pointer based on his response. After, you prompt him how many first names he wants to add to the pointer. So basically I'm trying to expand the same array by using realloc but I'm not sure if I'm using it correctly or not(Apparently not since it's not working)
Basically I want the first names that the user already inputted to stay as is, and for the program to start off asking the user for the next first name he wants to input. For example if the first time the user enters the number 2. Then he writes two names and then asks to add 2 more names, the program should keep the first 2 names and be ready to store at firstNames[2]. Thanks!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
int amount;
//Asking user for number of records to input
printf("Please indicate the number of records you want to enter:");
scanf("%d", &amount);
printf("\n");
//Declaring dynamic array for first names
char **firstNames = (char**)malloc(amount * sizeof(char));
for (int i = 0; i < amount; i++)
{
firstNames[i] = (char*)malloc(1 * sizeof(char));
}
//Prompting user for first name, last name, and scores
for (int count = 0; count < amount; count++)
{
printf("Enter first name for user %d:", count + 1);
scanf("%s", firstNames[count]);
}
int add;
printf("How many users do you want to add now:");
scanf("%d", &add);
int sum = amount + add;
firstNames = (char**)realloc(firstNames, sum * sizeof(char));
for (int count = amount; count < sum; count++)
{
printf("Enter first name for user %d:", count + 1);
scanf("%s", firstNames[count]);
}
return 0;
}
There are a number of areas where you are having trouble. As mentioned in my original comment, you must first allocate the memory correctly, before worrying about reallocating. Rather than calling realloc and assigning the return to firstNames, it is far better to create a temporary pointer to assign the return from realloc to. In the event realloc fails, it returns NULL. That means all existing data is lost because you just assigned firstNames = NULL. Using the temporary pointer allows your to test if the realloc succeeded before assigning the reallocated space to firstNames.
Going thought your code, there are several additional areas that can be improved. Always initialize your variables (to zero is fine). Why? Attempting to read from an uninitialized variable is Undefined Behavior (bad). Your input routines are critical. Especially using scanf and reading int/char data. You must insure you empty the input buffer before calling scanf again or it will use the newline (that results from pressing [enter]) as your next value causing your program to skip over the scanf statements that follow. You can use scanf to consume the newline to properly flush the input buffer (stdin) with careful choice of the format string.
When you get input validate it! Knucklehead users will enter anything.
When initializing pointer to pointers it is often better to use calloc for the initial allocation instead of malloc. calloc initializes all values to (zero) again preventing a read from an uninitialized variable.
Regarding program flow, you will want to minimize the number of loops and eliminate unnecessary blocks of code. If for no other reason, to lessen that chance of mistake. Think through your loops. You used multiple loops to count to the same number when all your operations could take place in one. This isn't a knock, this is just a suggestion to help you simplify your code.
When you ask for how many more users to enter before reallocating, what happens if 0 is entered? How should you handle it? Better to check and respond the way you want to, than leave it up to what the computer considers potentially undefined.
Those are the main points. I put together an example with those thoughts incorporated. It can always be improved, but I think this will help you handle the input issue and give you an example of simplifying the flow. While not necessary, I created a couple of functions to handle the printing and freeing of memory. Remember, if you allocate memory, you are responsible for keeping track of it and freeing it when your are done. Enough! Here is the example. Let me know if you have questions.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void print_users (char **array, int sz); /* funciton to print users */
void free_memory (char **array, int sz); /* function to free memory */
int main (void)
{
int amount = 0; /* always intialize all variables */
int i = 0;
//Asking user for number of records to input
printf("\nEnter the number of records to enter: ");
scanf("%d%*c", &amount); /* read int, discard newline */
printf("\n");
if (!amount) /* validate records to enter */
{
fprintf (stderr, "\nerror: invalid input.\n\n"); /* if realloc fails, error and exit */
return 1;
}
//Declaring dynamic array for first names
char **firstNames = calloc (amount, sizeof (*firstNames)); /* using your variable for sizeof (x) */
for (i = 0; i < amount; i++) /* prevents mistaken sizeof (wrong) */
{ /* calloc initializes to NULL (zero) */
firstNames[i] = malloc (sizeof (**firstNames)); /* same for malloc */
//Prompting user for first name, last name, and scores
printf (" first name for user %d : ", i + 1);
scanf ("%m[^\n]%*c", &firstNames[i]); /* read string and newline (discarded) */
}
int add = 0;
printf ("\nAny *additional* users to add: ");
scanf ("%d%*c", &add); /* read int, discard newline */
printf ("\n");
if (!add)
{
print_users (firstNames, amount);
free_memory (firstNames, amount);
return 0;
}
int sum = amount + add;
char **tmp = NULL;
tmp = realloc (firstNames, sum * sizeof (*firstNames)); /* never realloc actual pointer to data */
/* if realloc fails pointer set to NULL */
if (!tmp) /* validate realloc succeeded */
{
fprintf (stderr, "\nerror: reallocation failed.\n\n"); /* if realloc fails, error and exit */
return 1;
}
firstNames = tmp; /* now assign to pointer */
for (i = amount; i < sum; i++) /* why new var count, use i */
{
firstNames[i] = malloc (sizeof (**firstNames)); /* allocate new Names, prompt & store */
printf (" first name for user %d : ", i + 1);
scanf ("%m[^\n]%*c", &firstNames[i]);
}
print_users (firstNames, sum);
free_memory (firstNames, sum);
return 0;
}
void print_users (char **array, int sz)
{
printf ("\nUsers firstNames:\n\n"); /* output users collecte in firstNames */
int i = 0;
for (i = 0; i < sz; i++)
printf (" user[%d] %s\n", i, array[i]);
}
void free_memory (char **array, int sz)
{
int i = 0;
for (i = 0; i < sz; i++) /* free allocated memory */
if (array[i])
free (array[i]);
if (array)
free (array);
}
Example Usage:
$ ./bin/reallocptr
Enter the number of records to enter: 2
first name for user 1 : Jack
first name for user 2 : Jill
Any *additional* users to add: 2
first name for user 3 : Mike
first name for user 4 : Moe
Users firstNames:
user[0] Jack
user[1] Jill
user[2] Mike
user[3] Moe
Note: See Addendum below, otherwise 4-bytes of memory will remain un-freed at exit.
Addendum
As was pointed out, only a single char was allocated to each of the firstName[i] pointers which was insufficient for the full strings assigned. Generally, in practice firstName[i] string allocation can be handled automatically with functions such as strdup or scanf with an appropriate format string. To fully handle the strings with scanf, the following changes are required:
//Declaring dynamic array for first names
char **firstNames = calloc (amount, sizeof (*firstNames)); /* using your variable for sizeof (x) */
for (i = 0; i < amount; i++) /* prevents mistaken sizeof (wrong) */
{ /* calloc initializes to NULL (zero) */
// firstNames[i] = malloc (sizeof (**firstNames)); /* let scanf auto-allocate */
//Prompting user for first name, last name, and scores
printf (" first name for user %d : ", i + 1);
scanf ("%m[^\n]%*c", &firstNames[i]); /* read string and newline (discarded) */
}
...
for (i = amount; i < sum; i++) /* why new var count, use i */
{
// firstNames[i] = malloc (sizeof (**firstNames)); /* allocate new Names, prompt & store */
printf (" first name for user %d : ", i + 1);
scanf ("%m[^\n]%*c", &firstNames[i]);
}
changes to free_memory()
void free_memory (char **array, int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
if (array[i])
free (array[i]);
if (array)
free (array);
}
output/verification:
Enter the number of records to enter: 2
first name for user 1 : Jack
first name for user 2 : Jill
Any *additional* users to add: 2
first name for user 3 : Larry
first name for user 4 : Moe
Users firstNames:
user[0] Jack
user[1] Jill
user[2] Larry
user[3] Moe
==13690==
==13690== HEAP SUMMARY:
==13690== in use at exit: 0 bytes in 0 blocks
==13690== total heap usage: 10 allocs, 10 frees, 468 bytes allocated
==13690==
==13690== All heap blocks were freed -- no leaks are possible
char **firstNames = (char**)malloc(amount * sizeof(char));
This is a double pointer and memory needs to be allocated for pointers which points to your information.
So it should be
char **firstNames = malloc(amount * sizeof(char *));/* No need to cast malloc() */
Later you are doing realloc() for this memory and it is necessary for you to take care of realloc() failures.So use a temporary pointer to store the return value of realloc() and assign the address back to your firstNames.
firstNames[i] = (char*)malloc(1 * sizeof(char));
You are allocating a single byte here in each iteration in order to read strings you need more memory than this.
Some corrections in your memory allocations.
#define SIZE 10
char **firstNames = malloc(amount * sizeof(char *));
for (i = 0; i < amount; i++)
{
firstNames[i] = malloc(SIZE * sizeof(char));
}
First malloc is allocating memory for no of entries you want to store.
Since the entry are pointers to another memory, use malloc(amount * sizeof(char *))
The second malloc is nothing but, allocating memory for the actual strings you wan to store.
Where SIZE is the no of bytes for each entry.
So now you want to add more users, so you use realloc.
int sum = amount + add;
firstNames = realloc(firstNames, sum * sizeof(char *));
/* Add the following to your code */
for (i = amount; i < sum; i++)
firstNames[i] = malloc(SIZE * sizeof(char));
printf("Total Names: \n");
for ( i = 0; i < sum; i++)
printf("%s\n", firstNames[i]);
Here the second malloc is used for allocating memory for the newly added users.
It starts from (i = amount), since till amount memory is already allocated.

Adding a struct to an array using a pointer

I am fairly new to the C language and allocating memory/using pointers in general. Anyway, I was experimenting with reading a file, putting those values in a struct, etc. I know exactly what I want to do and of course the program runs but the output is incorrect and some kind of jumbled numbers and letters.
There is a text file with new information for each line. Each line represents one object.
This is how a line in the file might look:
meat sirloin 6.55 8 8.50 4
Overall I want to be able to store all of my PRODUCT objects in an array (so I have an array of structs). So I attempted to allocate memory with a pointer, use a line count, and then send the pointer to a function called read. In read I add each struct to the array via a pointer. The program doesn't crash, the output is just not correct and I have no clue why not. It's prob something with pointers. If anyone could help me I would really appreciate it. Any help at all would be great.
//prototype
void read(pointerToArr);
typedef struct
{
char supType[15];
char prodName[15];
double wholePrice;
int quantWhole;
double retPrice;
int retProdQuantity;
}PRODUCT;
FILE *fr;
int lineCount = 0;
int main()
{
PRODUCT *ptr;
int i;
char check[50];
fr = fopen("ttt.txt", "r");
while(fgets(check, sizeof(check), fr)!= NULL)
{
if(check[0] != '\n')
{
lineCount++;
}
}
// allocate memory for array based on line count.
PRODUCT prodContainter[lineCount];
ptr = (PRODUCT*)malloc(sizeof(PRODUCT)*lineCount);
ptr = prodContainter;
read(ptr);
//print after adding to array via pointer from other
//function. this was a test.
for(i = 0; i < lineCount; i++)
{
printf("%s ", prodContainter[i].supType);
printf("%s ", prodContainter[i].prodName);
printf("%f ", prodContainter[i].wholePrice);
printf("%d ", prodContainter[i].quantWhole);
printf("%f ", prodContainter[i].retPrice);
printf("%d\n\n", prodContainter[i].retProdQuantity);
}
return 0;
}
void read(PRODUCT *pointerToArr)
{
// objective in this method is to read in data from the file, create an object for every line and
// then use the pointer array to add those objects to prodConstainer up above.
char supplyName[15];
char productName[15];
double wholeP = 0;
int quantityWhole = 0;
double retailPrice = 0;
int retailProductQuant = 0;
while(fscanf(fr, "%s %s %lf %d %lf %d", supplyName, productName, &wholeP, &quantityWhole, &retailPrice, &retailProductQuant) == 6)
{
PRODUCT record;
int i;
strcpy(record.supType, supplyName);
strcpy(record.prodName, productName);
record.wholePrice = wholeP;
record.quantWhole = quantityWhole;
record.retPrice = retailPrice;
record.retProdQuantity = retailProductQuant;
for(i = 0; i < lineCount; i++)
{
pointerToArr[i] = record;
}
}
fclose(fr);
}
You never rewind the file, so all the reading after you count the number of lines fails.
What you're printing is just what happens to be in memory.
There are many ways to fix this, of course.
Rewind the file, using rewind()
Close the file and let your read() function (whose name collides with a POSIX standard function, btw) re-open the file. This would also involve removing the scary global variable fr.
Re-structure so you never count the number of lines, by just reading and letting the ptr array grow as necessary (see realloc()).
Also, you should really avoid casting the return value of malloc() in C. This:
ptr = (PRODUCT*)malloc(sizeof(PRODUCT)*lineCount);
is better written as:
ptr = malloc(lineCount * sizeof *ptr);
This does away with the cast, and also uses sizeof on a value of the type pointed at to automatically compute the proper number of bytes to allocate.

Resources