Trying to write a function that get names from the user - c

I tried to write a function, that get a number of candidates betwen 10 to 60,000,
and gets a name for each candidate...
This is what I wrote:
/********** Headers **********/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
/********** Consts **********/
const number_candidates;
/********** Functions **********/
void get_candidates(char *arr[256][256])
{
int counter = 1, i = 0, j =0;
int temp = 0;
printf ("Please enter the number of candidates: \n");
scanf ("%d", &temp);
while (temp < 10 && temp > 60000)
{
printf ("Please enter the number of candidates: \n");
scanf ("%d", temp);
}
const number_candidates = temp;
while (counter < number_candidates + 1)
{
printf ("Please enter the %d name: \n", counter);
fgets (arr, 256, stdin);
counter++;
}
}
int main(int argc, char *argv[])
{
int i = 0;
char can_names[256][256];
get_candidates(&can_names);
system("PAUSE");
return 0;
}
There is an error in getting the names into the arr...

You should avoid using arguments like this one: char *arr[256][256] ... what's the point of it? You should think about what your function will do. You want it to load names of candidates right? So you could define struct candidate with an attribute name within it:
typedef struct candidate{
char name[256];
} Candidate;
Another thing: why are you passing an address of your array to this function? You just want your array to be filled with data, you won't work with an array itself, thus it's enough to pass an array, not an address of it.
Then prototype of your function could be changed to void get_candidates(Candidate* candidates) which is much easier to read. And look how simple can usage of this function become:
Candidate candidates[256];
get_candidates(candidates);
And last thing: before you write function like that, try something simpler first (to find out what's happening there).
Here's an example:
#include <stdio.h>
typedef struct candidate{
char name[256];
} Candidate;
void get_candidates(Candidate* candidates){
scanf("%255s", candidates[4].name);
}
int main(int argc, char *argv[]){
Candidate candidates[256];
get_candidates(candidates);
printf("%s\n", candidates[4].name);
return 0;
}
In case you don't know the count of candidates before calling get_candidates, then it's better to change the prototype of this function to Candidate* get_candidates() so that it's clear that this function creates an array:
// caller is responsible for calling free on return value
Candidate* get_candidates(){
Candidate* candidates;
int count = 50; // here you found out the count
candidates = malloc(count*sizeof(Candidate));
fgets(candidates[4].name, 255, stdin);
return candidates;
}
int main(int argc, char *argv[]){
Candidate* candidates = get_candidates();
printf("%s\n", candidates[4].name);
free(candidates);
return 0;
}

You should call:
counter = 0;...fgets (arr[counter], 256, stdin);
You need walk one step for each loop.

Have a look at the documentation for scanf which indicates that variables need to be passed as a pointer as you did the first time you call scanf. Then have a look at your second call to scanf...
You're currently only assigning names to the first string in your array over and over again. Look at that while loop and in particular, how you're passing in the 'arr' variable. Have a look here for some inspiration.
To print out all of the names you need to loop over the array. You can find some examples of printing a list of strings here and here.

A few things are wrong:
First, you need space for 60000 names, yet you only allocate enough for 256. OK, we change
char can_names[256][256];
to
char can_names[60000][256];
and get... a segmentation fault, probably. That's because the array is using too much stack space. Change it to
static char can_names[60000][256];
so it's not on the stack.
Second, there's no need to take the address of the array - it's already passed as a pointer. Your function call changes to
get_candidates(can_names);
and the function signature is
void get_candidates(char arr[60000][256])
Third, you need a loop to read the entries one at a time. A for loop is easier to read:
for (counter = 0; counter < number_candidates; counter++)
{
printf ("Please enter the %d name: \n", counter);
fgets (arr[counter], 256, stdin);
}
Fourth, the condition
while (temp < 10 && temp > 60000)
should be
while (temp < 10 || temp > 60000)
(how can a number be both less than 10 and greater than 60000?) Once this is fixed, you can remove the initial read of temp since the loop will run at least once. Note that if you type a letter instead of a number now, the program will go into an infinite loop (it will repeatedly read the letter). Fixing this is left as an exercise.
Fifth, you don't need any headers except stdio.h. Also, the i and j variables are unused.
Edit: missed the scanf error. scanf takes addresses as parameters. it makes sense too: scanf needs somewhere to store a value, it doesn't care about the current value. So the call to scanf should be:
scanf ("%d", &temp);

Don't know if this would help but have a look at the code below.
It works dynamically ie. it allocated memory for desired no of candidates rather than assuming 60,000 of them.
/*
* Write a function, that get a number of candidates betwen 10 to 60,000, and gets a name for each candidate
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 256
int main(int argc, char*argv[]){
int i,n;
char **s;
printf("Enter the total number of candidates\n");
scanf("%d",&n);
//error condition
if(n<10 || n>60000){
printf("Sorry number of candidates should be between 10 to 60,000\n");
return -1;
}
//allocate memory
s = malloc(sizeof(char*)*n);
//get the data
for(i=0;i<n;i++){
s[i] = calloc(MAX,sizeof(char));
printf("Enter the candidate number %d's name:\n",i+1);
//fgets(s[i],MAX,stdin);
scanf("%s",s[i]);
}
//Display the data
printf("\nDetails of all the Candidates\n\n");
for(i=0;i<n;i++){
printf("Candidate number %d's name:%s\n",i+1,s[i]);
}
//Free the memory
for(i=0;i<n;i++){
free(s[i]);
}
free(s);
return 0;
}
I had a problem with fgets it was skipping the first candidate info. Any help would be appreciated.. I tried flush(stdin) but did not solve the issue.

Related

What syntax am i missing out on regarding char arrays and pointers to them

I was doing some testing for a program of mine and was wondering why the program was crashing when entering my function. Don't mind the logic of the program, since i was still in the phase of making sure i understood how to use my tools at hand.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Constants */
#define HEX_CAPITAL_LETTERS_BEGIN 65
#define HEX_CAPITAL_LETTERS_END 90
#define HEX_NUMBERS_BEGIN 48
#define HEX_NUMBERS_END 57
#define EXIT_SUCCES 0
/* Prototypes */
void codeToField(char *charArray, int i, int hexFloor, int hexCeil, char *outputArray);
/* Main Function */
int main(void) {
char *code, warehouse, product, qualifiers;
int i = 0;
printf("Enter a MMOC product code: ");
scanf("%s", &code);
codeToField(code, i, HEX_CAPITAL_LETTERS_BEGIN, HEX_CAPITAL_LETTERS_END, &warehouse);
codeToField(code, i , HEX_NUMBERS_BEGIN, HEX_NUMBERS_END, &product);
strcpy(&qualifiers, code + i);
printf("\n\nWarehouse: %s\nProduct: %s\nQualifiers: %s\n", &warehouse, &product, &qualifiers);
return EXIT_SUCCES;
}
void codeToField(char *charArray, int i, int hexFloor, int hexCeil, char *outputArray) {
int j = 0;
while (charArray[i] >= hexFloor && charArray[i] <= hexCeil) {
outputArray[j] = charArray[i];
i++;
j++;
}
}
Thanks in advance.
First, this does not do what you want:
char *code, warehouse, product, qualifiers;
The only pointer is code, the other are just a single char. You're printing them as strings with printf, and you use warehouse and product as outputArray in your function. They need to be pointers (or arrays) too:
char *code, *warehouse, *product, *qualifiers;
Then you need memory. The pointers are still uninitialized, so any reading from them is undefined behavior.
You can either allocate memory with automatic storage duration (on the stack) or dynamically (on the heap).
Stack:
char codestr[100];
code = codestr;
but then, you could also just have declared code as
char code[100];
to avoid to have two variables.
If you want to allocate the memory dynamically, you would use malloc:
code = malloc(100);
Don't forget to free the memory again:
free(code);
warehouse, product, qualifiers all need memory too. Some of the array sizes could be deduced form the defined constants.
char *code, warehouse, product, qualifiers;
int i = 0;
printf("Enter a MMOC product code: ");
scanf("%s", &code);
Here, code is an uninitialized pointer to memory so once you do the scanf call, your program is hosed.
I think you want something more like
char code[100];
printf ("Enter a MMOC product code: ");
scanf ("%s", code);
The reason is because code has no memory allocated to it. It is an uninitialized pointer. Try this instead:
// ...
char myString[16], *code, warehouse, product, qualifiers;
code = &myString[0];
int i = 0;
printf("Enter a MMOC product code: ");
scanf("%15s", code);
// ...

How to reset allocated memory and resources in c?

My program consists of a Menu, where you can select 1 of 2 options.
The second is just to exit the program. The first, however, is where you can find a specific sequence of bits that you choose, in a separate ".txt" file with 100.000 lines.
It does what I want the first time, and then returns to the Menu.
The problem is when the user goes for a second (or more) search. The program prints on screen random information.
It seems like I didn't do a "reset" of the resources, memory or values on the first search.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
char ID[8];
char content[2048];
int distance;
} DATA;
void search(){
FILE *f;
DADO *z=NULL;
long int tot=0;
int a;
int c;
int i;
int j=1;
int k=0;
char e;
char b[2048];
printf("\n");
f=fopen("DANGER_DB_LARGE.txt", "r");
printf("\n");
printf("How many results do you wish?\n");
scanf("%d",&a);
printf("Introduce the sequence:\n");
scanf("%s",b);
c=strlen(b);
printf("\n");
z=(DATA*)realloc(z,(++tot)*sizeof(DATA));
while(e!=EOF){
e=fgetc(f);
if(k<8){
z[tot-1].ID[k]=e;
}
else if(k==8 && e=='\t'){
continue;
}
else if(k>=9 && e!='\n'){
z[tot-1].content[k-9]=e;
}
else if(e=='\n'){
k=(-1);
z=(DATA*)realloc(z,(++tot)*sizeof(DATA));
}
k++;
}
for(i=1; i<=tot; i++){
distance(z,i,c,b);
}
free(z);
fclose(f);
}
I proceed to store the ID and content of every single one of those 100.000 lines of text. I end the function by doing free(z), but when I search again the program just prints random stuff.
Use of uninitialised variables without an intervening assignment is undefined behaviour. It may work on the first Wednesday of every month, on the first time through the loop, only when the boss is looking, ...
int e; // originally was char
//...
while (e != EOF) { // uninitialised, no intervening assignment
Realloc returns void by the way
void *realloc(void *ptr, size_t size)
plus it takes a pointer as input so its pass by reference.
update: This function returns a pointer to the newly allocated memory, or NULL if the request fails.
my bad.

Handling struct functions in C - Can enter an array but not an int

I'm having a bit of trouble with using structs inside functions.
The program is meant to:
Create an array containing five structures of type Person
Allow the user to enter the datatypes through use of functions.
Print the five entered people one by one.
While point 1 and 3 work fine, it's point 2 that I'm having issues with. The name will enter and print just fine, but regardless of what I enter into scanf it returns and prints '-858993460'.
int calls = 0;
typedef struct person {
char name[20];
int bYr;
}Person;
int main(int argc, char** argv) {
Person psn[5];
for (int i = 0; i < 5; i++) {
printf("Please enter the name and birthyear of person %d.", i+1);
personName(psn[i].name);
personBirthyear(psn[i].bYr);
}
for (int i = 0; i < 5; i++) {
printPerson(psn[i]);
}
getchar();
return 0;
}
int personBirthyear(int birthyear) {
printf("\nBirthyear: ");
scanf("%d", &birthyear);
getchar();
return birthyear;
}
char* personName(char* pername) {
printf("\nName: ");
fgets(pername, 20, stdin);
return pername;
}
void printPerson(Person prsn) {
printf("Person %d:\nBirthyear: %d\nName: %s\n", calls+1, prsn.bYr, prsn.name);
calls++;
}
Easy enough: you are not updating a Person' year, but you are passing it as a copied argument (you copy an int in personBirthyear and a pointer to a char in personName).
Thus:
personName(psn[i].name); // works
personBirthyear(psn[i].bYr); // fails
You need to pass the address of year, and work with pointers here:
int personBirthyear(int* birthyear) {
printf("\nBirthyear: ");
scanf("%d", birthyear);
getchar();
return *birthyear;
}
Or, you could also remove the birth year:
int personBirthyear() {
int birthyear;
printf("\nBirthyear: ");
scanf("%d", &birthyear);
getchar();
return birthyear;
}
Then: psn[i].bYr = personBirthyear();
In any case, you don't check the result of scanf; thus you don't know if you actually read a number. You should check it:
int n = scanf("%d", &birthyear);
getchar();
if (n != 1) return -1;
return birthyear;
The getchar is still mandatory to "clear" away the character that made scanf fail (otherwise, it would be reread again and again...).
you have some problems in your code :
You are not receiving a output while returning from function.
Without function declaration compiler will confuse about function return type.
you should know if you want to accept modified data between function call, data should provide as pass by reference. in your program, you give data to personBirthyear() function as call by value.

How to find out how much numbers are in array

EDIT : Ok,so answer was told by #Mischo5500. Thank you all,guys
How to find out how much numbers are in array except space? My program will find out length of array, until user input will be space and that is the problem. So if I have inserted "10 20 300", the length will be 2. I have expected 3,like three numbers,which were inserted.And I don't know,how much numbers will user type in. I have already tried strlen(p),it was the same thing. Can you help me? Thanks!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
float p[1000];
scanf("%f",p);
int length=(sizeof(p)/sizeof(float));
printf("%d",length);
return 0;
}
If i tike it right (sorry if not), you want to calculate number of entered float values. It is easier for you to insert them in string format and convert them to float after processing, if you don't know number of arguments, that will be typed in. Here is how your code can look like for example, float numbers are in val variable, number of inserted values is in length variable.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char p[1000];
float val[1000];
int length = 0;
char* itr;
fgets(p, sizeof(p), stdin);
itr = strtok(p, " ");
while(itr != NULL)
{
val[length] = atof(itr);
itr = strtok(NULL, " ");
length++;
}
printf("%d",length);
return 0;
}
EDIT: If you want "length" of first element, just use strlen() on first token
itr = strtok(p, " \n");
if(itr)
{
length = strlen(itr);
val[length] = atof(itr);
}
You can take in the user inputs in the form of command-line arguments which get passed in to the program as
int main(int argc, char *argv[])
That will give you the entire length of arguments. You would convert each of the arguments argv[i] to numbers.

Function error 'expected expression before char'?

I have created the following program which allows a user to guess a word 3 times before ending the program. I'm using a function to read the users input. When I compile the program I get the error 'expected expression before char'. Some feedback would be great thanks!
#include <stdio.h>
#include <string.h>
void get_user_input(char *guess[10]);
void get_user_input(char *guess[10])
{
printf("Please guess the word: \n");
scanf("%s", guess);
}
int main(void)
{
const char secret[10] = "pink";
char guess[10];
int i;
for (i=0; i < 3; i++)
{
get_user_input(char *guess[10]);
if (strcmp(secret, guess)==0)
{
printf("Your guess was correct");
return 0;
}
else
{
printf("Your guess was incorrect. Please try again\n");
}
}
return 0;
}
You have an extra char here:
for (i=0; i < 3; i++)
{
get_user_input(char *guess[10]);
Just get rid of it. You just need to pass the variable in.
get_user_input(guess);
EDIT :
The other problem seems to be this function:
void get_user_input(char *guess[10]);
change it to this:
void get_user_input(char *guess)
{
printf("Please guess the word: \n");
scanf("%s", guess);
}
and it should work. However, be aware that you run the risk of overrunning your guess array.
Inside the loop, write
get_user_input(guess);
instead of
get_user_input(char *guess[10]);
.
In addition, you should delete the useless prototype
void get_user_input(char *guess[10]);
and change the following function's signature to
void get_user_input(char * guess)
to let a pointer to the first char of the array be passed instead of a pointer to a pointer to the first char which will not compile. A side issue is that char *guess[10] means an array of 10 pointers to char.
PS: It helps to post the offending line number in addition to the error message.
PPS: You have a buffer overrun memory error if the use enters long answers. You can use fgets to avoid this.

Resources