Problem reading in string in C for dynamic number inputs - c

I'm a Noob, struggling with C. I'm having a hard time wrapping my head around pointers, arrow -> and dot . notation. I am working on a very simple program that has 1 struct, but I am unsure of how to get users to input strings without using the <cs50.h> header (which I need to understand for the harder problem I am also trying to wrap my head around).
//#include <cs50.h>
#include <stdio.h>
#include <string.h>
// create a struct, call it pupils
typedef struct
{
char *name;
char *dorm;
}
pupils;
int main(void)
{
// Allocate space for students - generally dynamic, here static
int enrollment = 2;
// create variable 'idinfo', which contains (enrollment) number of structs of type pupils
pupils idinfo[enrollment];
// Prompt for students' names and dorms
for (int i = 0; i < enrollment; i++)
{
// Not the way to do this given various error codes.....
char idinfo[i].Name[20];
char Dorm[20];
// gets idinfo[i].Name
scanf("%s", idinfo[i].Name);
//idinfo[i].name = printf("%s", Name);
// Below syntax works fine when <string.h> header included
idinfo[i].dorm = get_string("Dorm: ");
}
// Print students' names and dorms
for (int i = 0; i < enrollment; i++)
{
printf("%s is in %s.\n", idinfo[i].name, idinfo[i].dorm);
}
}

Assuming you do not want to use the cs50 magic, you will have to allocate and deallocate strings. From your code I will also assume that the input strings are supposed to be shorter than 20 characters. The following code does not even ensure that it is true but will not crash either but will simply give unexpected results.
Code could be:
int main(void)
{
// Allocate space for students - generally dynamic, here static
int enrollment = 2;
// create variable 'idinfo', which contains (enrollment) number of structs of type pupils
pupils idinfo[enrollment];
// Prompt for students' names and dorms
for (int i = 0; i < enrollment; i++)
{
// allocate memory for idinfo[i] pointers:
idinfo[i].name = malloc(20);
scanf("%19s", idinfo[i].name);
idinfo[i].dorm = malloc(20);
scanf("%19s", idinfo[i].dorm);
}
// Print students' names and dorms
for (int i = 0; i < enrollment; i++)
{
printf("%s is in %s.\n", idinfo[i].name, idinfo[i].dorm);
}
// free allocated memory
for (int i = 0; i < enrollment; i++)
{
free(idinfo[i].name);
free(idinfo[i].dorm);
}
}

You probably want something like this:
#include <cs50.h> // needed for get_xxx functions and other cs50 stuff
...
// Prompt for students' names and dorms
for (int i = 0; i < enrollment; i++)
{
idinfo[i].name = get_string("Name: ");
idinfo[i].dorm = get_string("Dorm: ");
}
But this should be covered in the documentation you were given.
My advice is not using scanf at all but using only the cs50 get_xxx input methods.
And beware: the cs50 string is not a real "string" type but merely the same thing as char *.

Thanks to Serge, I was able to get my code compiling, which is below.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// create a struct, call it pupils
typedef struct
{
char *name;
char *dorm;
}
pupils;
int main(void)
{
// Allocate space for students - generally dynamic, here static
int enrollment = 2;
// create variable 'idinfo', which contains (enrollment) number of structs of type pupils
pupils idinfo[enrollment];
// Prompt for students' names and dorms
for (int i = 0; i < enrollment; i++)
{
// allocate memory for idinfo[i] pointers:
idinfo[i].name = malloc(20);
idinfo[i].dorm = malloc(20);
printf("Enter student %d's Name ", i+1);
scanf("%19s", idinfo[i].name);
printf("Enter student %d's dorm ", i+1);
scanf("%19s", idinfo[i].dorm);
}
// Print students' names and dorms
for (int i = 0; i < enrollment; i++)
{
printf("%s is in %s.\n", idinfo[i].name, idinfo[i].dorm);
}
// free allocated memory
for (int i = 0; i < enrollment; i++)
{
free(idinfo[i].name);
free(idinfo[i].dorm);
}
}

Related

How can I free memory used by malloc() outside a function?

I am trying to free the memory allocated by my getSongInfo function, I have tried using a pointer to the function call but I get an error "cannt assign int to type int*" error. Any help would be great as the current way I have seems like it may work, but I might be completely wrong. Thanks!
Original Attempt:
int *memPtr = NULL
memPtr = getSongInfo(&fillPtr[arrayCounter], tempArtist[counter], tempSong[counter]);
Gives error!
Current Attempt:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#pragma warning(disable:4996)
int getSongInfo(struct songInfo *pFillInfo, char *artistName, char *songName);
void printSongInfo(struct songInfo songList[10]);
struct songInfo {
char *songArtist;
char *songTitle;
};
int main(void)
{
struct songInfo *fillPtr;
struct songInfo songList[10];
fillPtr = &songList[0];
char tempArtist[10][30];
char tempSong[10][30];
int *memPtr = NULL;
int i = 0;
int counter = 0;
int arrayCounter = 0;
while (counter != 10)
{
printf("Please enter the artist name: ");
fgets(tempArtist[counter], sizeof(tempArtist[counter]), stdin);
tempArtist[counter][strcspn(tempArtist[counter], "\n")] = 0;
printf("Please enter the song name: ");
fgets(tempSong[counter], sizeof(tempSong[counter]), stdin);
tempSong[counter][strcspn(tempSong[counter], "\n")] = 0;
getSongInfo(&fillPtr[arrayCounter], tempArtist[counter], tempSong[counter]);
printf("Song and Artist Captured! \n");
counter++;
arrayCounter++;
}
printSongInfo(fillPtr);
free(fillPtr->songArtist);
free(fillPtr->songTitle);
}
int getSongInfo(struct songInfo *pFillInfo, char *artistName, char *songName)
{
pFillInfo->songArtist = (char*)malloc(strlen(artistName) + 1);
pFillInfo->songTitle = (char*)malloc(strlen(songName) + 1);
strcpy(pFillInfo->songArtist, artistName);
strcpy(pFillInfo->songTitle, songName);
return 1;
}
void printSongInfo(struct songInfo songList[10])
{
int counter = 0;
while (counter != 10)
{
printf("%-35s %-35s\n", songList[counter].songArtist, songList[counter].songTitle);
counter++;
}
}
Your getSongInfo function does not return a pointer, so attempting to put the return value into a variable and then free it is pointless. The pointers in question are inside the struct songInfo, specifically, the fillPtr variable (which is actually redundant, since songList and fillPtr point to the same location).
In addition, please be aware that strcspn will not always return a valid index. If it does not find a match, it will return the length of the first argument.
I think this is more like what you are trying to do:
int main(void)
{
const int numSongs = 10;
struct songInfo songList[numSongs];
char tempArtist[30];
char tempSong[30];
int i;
int newline_idx;
for (i = 0; i < numSongs; ++i)
{
printf("Please enter the artist name: ");
fgets(tempArtist, sizeof(tempArtist), stdin);
newline_idx = strcspn(tempArtist, "\n");
if (newline_idx < sizeof(tempArtist))
tempArtist[newline_idx] = 0;
printf("Please enter the song name: ");
fgets(tempSong, sizeof(tempSong), stdin);
newline_idx = strcspn(tempSong, "\n");
if (newline_idx < sizeof(tempSong))
tempSong[newline_idx] = 0;
getSongInfo(&songList[i], tempArtist, tempSong);
printf("Song and Artist Captured! \n");
}
for (i = 0; i < numSongs; ++i)
{
free(songList[i].songArtist);
free(songList[i].songTitle);
}
}
You might consider separating the code for free()ing each struct into its own function.
You might also consider heeding that compiler warning instead of ignoring it, as Bodo commented. Careless handling of strings from stdin is dangerous.

How to search on struct char c?

#include<stdio.h>
#include<stdlib.h> //libraries
#include<string.h>
#define ARRAY_SIZE 4 //define the array size is 4
Declare a Person structure containing the following two data members: name and age.
struct Person
{
char name[20];
int age;
};
Define fillPersons function that takes an empty array of Persons, and fills the array.
void fillPersons(struct Person * myPs);
For function using
struct Person p[ARRAY_SIZE];
Define searchPerson function that takes an array of Persons, and the name to search for. The function will return the corresponding age if the person is found, -1 otherwise.
int searchPerson(struct Person * myPs, char * myName);
Define printPersons function that takes an array of Persons, and prints the content of the array.
void printPersons(struct Person * myPs);
Main Fuction
int main()
{
struct Person p[ARRAY_SIZE];
int a;
int isFound;
char myName[20];
Switch case for user interface
do
{
printf("1)FILL ARRAY\n");
printf("2)SEARCH BY NAME\n");
printf("3)PRINT ARRAY\n");
printf("4)EXIT\n");
printf("Search Operation:");
scanf_s("%d", &a);
switch (a)
{
case 1:fillPersons(p); break;
I write the main part of searching but i cant fill the function.
case 2:printf("\Give the name to search for:");
scanf_s("%s", &myName);
isFound = searchPerson(p, myName);
if (isFound == -1)
{
printf("%s not avaible in the array. \n", myName);
}
else
{
printf("The age of %s is %d.\n", myName, isFound);
}
break;
After this part it is okay to read names and ages but cant do it searching part.
case 3:printPersons(p); break;
case 4:printf("\nProgram exits ..."); exit(0);
}
} while (a != 4);
system("pause");
return 0;
}
It is okay this scanf part
void fillPersons(struct Person * myPs)
{
int i;
for (i = 0; i < 4; i++)//defining 4 person i<4
{
scanf_s("%20s", p[i].name,_countof(p[i].name));//if i dont do _coutof
scanf_s("%d", &p[i].age); // i get null.ptr error
} // on visiual studio
}
Printing the student names and ages
void printPersons(struct Person * myPs)
{
int i;
for (i = 0; i < 4; i++)
{
printf("%s %d", p[i].name, p[i].age);
}
}
But i dont know how to fill with inside on fuction?
int searchPerson(struct Person * myPs, char * myName)
THE OUTPUT SHOULD BE LIKE THIS
Seems the function you are missing is strcmp to compare two strings.
It could be like:
int searchPerson(struct Person * myPs, char * myName)
{
int i;
for (i = 0; i < ARRAY_SIZE; i++)
{
if (strcmp(myPs[i].name, myName) == 0)
{
return myPs[i].age;
}
}
return -1;
}
In general notice:
When you pass the array to a function as struct Person * myPs, you must use myPs inside the function. Further you should use the defined array size instead of hard coding a 4.
So your printPersons should be:
void printPersons(struct Person * myPs)
{
int i;
for (i = 0; i < ARRAY_SIZE; i++)
{
printf("%s %d", myPs[i].name, myPs[i].age);
}
}
Same applies to fillPersons
First thing, you put in your question all the functions except the one that is giving you problems: searchPerson.
Then, your error is with this instruction:
scanf_s("%s", &myName);
Accordingly that you declared myName as a char pointer, this way, you're assigning the string to the address of myName, not to the memory cells it's pointing to.
Instead, this should be:
scanf_s("%s", myName);

array of structs in c-user input

I am new to programming in general and to C in particular.
I am trying to write a program that uses an array of structs, but I am experiencing problems if that struct contains strings.
Somehow the compiler crashes after the user has given the last input.
The struct below is just a simplified version containing only one item, because the problem seems to be reading strings into the array.
Any help is much appreciated, thanks in advance.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
char* name;
}student;
int main()
{
int size;
printf("enter number of entries\n");
scanf("%d" , &size);
student* all=malloc(size*sizeof(student));
int i;
for(i=0;i<size;i++)
{
printf("enter name\n");
scanf("%s" , all[i].name);
}
return 0;
}
Before taking input scanf("%s" , all[i].name); , you need to allocate memory to all[i].name .
An example-
for(i=0;i<size;i++)
{
all[i].name=malloc(20*sizeof(*(all[i].name)));
if(all[i].name!=NULL){
printf("enter name\n");
scanf("%19s" , all[i].name);
}
}
//use these strings
for(i=0;i<size;i++){
free(all[i].name); //free the allocated memory
}
free(all);
Or in your structure instead of char * ,declare name as a char array (if you don't want to use dynamic allocation)-
typedef struct{
char name[20]; //give any desired size
}student;
/* no need to free in this case */
No memory is allocated for the students names (char* name), so when trying to scanf to that pointer, invalid memory is accessed and the program crashes.
The easiest way is to declare name as an array: char name[28];
The return value of malloc() needs to be checked too, in case there was problem allocating the memory for the students, which would return a NULL pointer. At the end, the allocated memory needs to be freed with free().
For example:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char name[28];
unsigned int age;
} student;
int main()
{
size_t size = 0;
printf("\nEnter number of entries: ");
scanf("%zu", &size);
// add some check for size
student* students = (student*)malloc(size * sizeof(student));
if (students == NULL) {
printf("\nProblem with allocating memory:\n"
" - size: %zu\n"
" - total size needed: %zu\n",
size, size * sizeof(student));
return 0;
}
for (size_t i = 0; i < size; ++i) {
printf("Enter name: ");
scanf("%27s", students[i].name);
printf(" Enter age: ");
scanf("%u", &students[i].age);
}
printf("\nList of students:\n");
for (size_t i = 0; i < size; ++i) {
printf("%s (%u)\n", students[i].name, students[i].age);
}
free(students); // free the allocated memory
return 0;
}

Can't more than two strings compare?

If we compared integers we would assign one of them as the largest/smallest one.
However, when I try comparing more than two strings, I can't manage assaigment.
In my code "for loop" compares two of the strings. This is good method but I need to compare one of them to the others individually. (I can predict that I need to use two for loop, but also I can't implement) What is your suggestions?
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct wordSorting
{
char name[15];
int i = 0;
};
int main()
{
wordSorting *wordElement = (wordSorting *)malloc(sizeof(wordSorting));
wordElement = (wordSorting *)malloc(sizeof(wordSorting));
printf("-- Enter three person name --\n\n");
for (wordElement->i = 0; wordElement->i < 3; wordElement->i++)
{
printf("Enter %d. person name: ", wordElement->i + 1);
scanf("%s", wordElement[wordElement->i].name);
}
printf("\n");
for (wordElement->i = 0; wordElement->i < 3; wordElement->i++)
{
if ((strcmp(wordElement[wordElement->i].name, wordElement[wordElement->i + 1].name))<0)
{
printf("%s", wordElement[wordElement->i].name);
}
}
}
First
typedef struct wordSorting
{
char name[15];
int i = 0;
};
Members of typedef/struct cannot be initied.
That is not the way to define a typedef, change it as:
typedef struct
{
char name[15];
int i;
}wordSorting;
Second:
wordElement = (wordSorting *)malloc(sizeof(wordSorting));
makes no sense. malloc returns void pointer, and you already init your variable at the first element in the first line of code.
And, as someone edited: do not cast malloc return, please.
Third, :
wordSorting *wordElement = (wordSorting *)malloc(sizeof(wordSorting));
wordElement = (wordSorting *)malloc(sizeof(wordSorting));
printf("-- Enter three person name --\n\n");
for (wordElement->i = 0; wordElement->i < 3; wordElement->i++)
{
printf("Enter %d. person name: ", wordElement->i + 1);
scanf("%s", wordElement[wordElement->i].name);
}
You are allocating space for one element, no array are defined then wordElement[wordElement->i].name is undefined Behaviour.
Finally
I don't know what compiler are you using, but gcc cannot compile such a bad code full of errors...
Suggestion.
What I think you need is to use array, but you must allocate the number of member you need, by:
wordSorting *wordElement = malloc(sizeof(wordSorting)*num_of_elements);
or simply, using a local array:
wordSorting wordElement[num_of_elements];

dynamic array of structs in C

I am trying to learn about structs, pointers, and dynamic arrays in C. I don't understand how to create a dynamic array of structs using pointers. My code doesn't work, and I don't know what's wrong with it. I have seen several examples of dynamic arrays, but non with structs. Any help would be appreciated. Please give some explanation, not just code snippets as I do want to understand not just solve this problem.
#include<stdio.h>
#include<stdlib.h>
#include <string.h>
struct *struct_array;
int i,m,n,p;
struct data
{
char inputA[20];
char inputB[20];
};
struct data get_data()
{
struct data thisdata;
printf("Please enter input A\n");
scanf("%s", thisdata.inputA);
printf("Please enter input B\n");
scanf("%s", thisdata.inputB);
return thisdata;
}
void Output(struct data struct_array, int n)
{
int index = 0;
for(i = 0; i<n ;i++)
{
printf("%s ", struct_array[i].inputA);
printf("%s ", struct_array[i].inputB);
}
}
void resizeArray(int n)
{
struct_array = (int*)realloc(n*sizeof(int));
}
void mainMenu()
{
printf("Please select from the following options:\n");
printf("1: Add new students to database\n");
printf("2: Display current student database contents\n");
printf("3: exit the program\n");
scanf("%d", &p);
if(p == 1)
{
printf("Please enter the number of students to register:\n");
scanf("%d", &n);
resizeArray(n);
for(i = n; i<n ;i++)
{
struct_array[i] = get_data();
}
}
else if(p == 2)
{
Output(struct_array, n);
}
else
{
free(struct_array);
exit(0);
}
}
int main()
{
struct_array = (int*)realloc(2*sizeof(int));
mainMenu();
}
You have several errors in your source code:
struct *struct_array; (l. 5)
What does it mean? Did you want to write struct data *struct_array?
printf("%s ", struct_array[i].inputA); (l.32 & l. 33)
The argument struct_array masks the global declaration, and it is not an array. Why did you add this argument?
struct_array = (int *)realloc(n * sizeof(int)); (l. 39)
You have forgotten an argument. Did you want to use malloc instead? Besides, the cast is not necessary (and incorrect!).
Unless you are using an hosted environnment and C99/C11, you should return a value from main.
Your variable index is not used. Why did you declare it?
for(i = n; i < n; i++) (l. 53)
You won't have any iteration here...
The following code works as expected.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* TODO: Avoid global variables. */
struct data *struct_array;
struct data {
char inputA[20];
char inputB[20];
};
/*
* TODO: Try to avoid passing your structure (40 bytes + padding)
* without pointer.
*/
struct data get_data(void)
{
struct data thisdata;
printf("Please enter input A\n");
/* TODO: Avoid using `scanf` for human inputs. */
scanf("%s", thisdata.inputA);
printf("Please enter input B\n");
scanf("%s", thisdata.inputB);
return thisdata;
}
void Output(size_t n)
{
size_t i;
for (i = 0; i < n; i++) {
printf("%s ", struct_array[i].inputA);
printf("%s ", struct_array[i].inputB);
}
}
void resizeArray(size_t n)
{
/* TODO: Handle reallocations errors. */
struct_array = realloc(struct_array, n * sizeof *struct_array);
}
void mainMenu(void)
{
size_t i, n;
int p;
/* TODO: Use a loop ? */
printf("Please select from the following options:\n");
printf("1: Add new students to database\n");
printf("2: Display current student database contents\n");
printf("3: exit the program\n");
scanf("%d", &p);
switch (p) {
case 1:
printf("Please enter the number of students to register:\n");
scanf("%u", &n);
resizeArray(n);
for (i = 0; i < n; i++)
struct_array[i] = get_data();
break;
case 2:
Output(n);
break;
}
}
int main(void)
{
struct_array = malloc(2 * sizeof(int));
mainMenu();
free(struct_array);
return 0;
}
Your definition
struct *struct_array;
is erroneous. You must use the name of your type, the data.
struct data *struct_array;
This way you can allocate the array
struct_array = malloc(MaxNumElements * sizeof(struct data));
and later you should free the memory
free(struct_array);
EDIT: Type definition must occur before the var declaration.
struct data ....
struct data* your_variable;
P.S. If you do not want to type struct keyword each time you use the data type, use the typedef:
typedef struct data_s
{
char inputA[20];
char inputB[20];
} data;
Do you know how to use typedef?
I would suggest it, makes your code easier to understand and you won't have to be typing the word struct a thousand times. Also you could treat the new type similar to the primitive types (ints, chars, etc), just don't forget to use the dot (.) to access the individual fields you might want.
You could type for instance:
typedef struct{
char inputA[20];
char inputB[20];
} data;
Now you could declare variables like this:
data data_variable;
data *pointer_to_data;
And to you could allocate memory as follows:
pointer_to_data = (data*) malloc(sizeof(data)* N);
where N is the amount of struct data you want to allocate. Same works for realloc.
struct_array = (int*)realloc(2*sizeof(int));
By the above statement you are trying to assign address of an int to a pointer of type struct data.
You need to use:
struct_array = (struct data*)realloc(2*sizeof(struct data));

Resources