Properly buffering and validating string - c

I am getting a bit of an error in my program, it is somewhat basic but here is my error: I am trying to properly input a series of strings into a structure and it seems like user input is ending at the wrong spot.
#include <stdio.h>
#include <string.h>
#define buffer 256
struct Fisher
{
char SSN[8]; //9 digit max
char First_Name[12];
char Last_Name[15];
char Phone[10];
char Email[35];
}typedef Fisher;
void getFisher(Fisher* pfisher, int i);
void dispFisher(Fisher* pfisher, int i);
void Fisherman_Menu(Fisher* pfisher, int i);
int main()
{
int i = 0;
Fisher fisherarray[3];
Fisher* pfisher = &fisherarray[0];
Fisherman_Menu(pfisher, i);
return 0;
}
void Fisherman_Menu(Fisher* pfisher, int i)
{
for(;;)
{
fflush(stdin);
printf("-1-Register Fisherman\n");
printf("-2-Search Fisherman\n");
printf("-3-Go back to Main Menu\n");
fflush(stdin);
int choice=0;
scanf(" %d", &choice);
if (choice == 1)
{
fflush(stdin);
getFisher(pfisher, i);
i++;
}
if (choice == 2)
{
fflush(stdin);
dispFisher(pfisher, i);
}
else if (choice == 3)
{
break; /* Break out of loop */
}
else
printf("Anything else?\n");
}
/* When this function returns, you get back to the main menu */
}
void getFisher(Fisher* pfisher, int i)
{
char input[buffer];
char* pinput = NULL;
//===============================
printf("Enter Social Security Number: ");
pinput = fgets(input, buffer, stdin);//validate
strcpy((pfisher+i)->SSN, pinput);
//(pfisher+i)->SSN = atoi(pinput);
//==============================
printf("Enter first name: ");
pinput = fgets(input, buffer, stdin);//validates name
strcpy((pfisher+i)->First_Name, pinput);
//==============================
printf("Enter last name: ");
pinput = fgets(input, buffer, stdin);//validates name
strcpy((pfisher+i)->Last_Name, pinput);
//==============================
printf("Enter phone number as a 10 digit number (without any
dashes or spaces): ");
pinput = fgets(input, buffer, stdin);//validate phone
strcpy((pfisher+i)->Phone, pinput);
//(pfisher+i)->Phone = atoi(pinput);
//===============================
printf("Enter email address: ");
pinput = fgets(input, 20, stdin);//validates name
strcpy((pfisher+i)->Email, pinput);
}
void dispFisher(Fisher* pfisher, int i)
{
int len;
int pen;
printf("ssn is equal to: %s\n", ((pfisher+0)->SSN));
printf("First Name is equal to: %s\n", ((pfisher+0)->First_Name));
printf("ssn is equal to: %s\n", ((pfisher+1)->SSN));
printf("First Name is equal to: %s\n", ((pfisher+1)->First_Name));
len = strlen(((pfisher+0)->SSN));
printf("string length = %d\n", len);
pen = strlen(((pfisher+1)->SSN));
printf("string length = %d\n", len);
/*
int arr = 0;
char searchSSN[9];
printf("Enter SSN: ");
scanf("%s", &searchSSN);
for(arr = 0; arr < i; arr++)
{
if(strcmp(&searchSSN, (pfisher+arr)->SSN) == 0)
{
//printf("I is equal to: %s\n", (pfisher+i)->SSN);
printf("Fisher\n");
printf("-------------------------------------------\n");
printf("%d \n %s \n %s \n %s \n %s ", (pfisher + arr)->SSN, ((pfisher+arr)->First_Name), ((pfisher+arr)->Last_Name), ((pfisher+arr)->Phone), (pfisher+arr)->Email);
printf("-------------------------------------------\n");
}
}
*/
}
My output for SSN is getting messed up and becoming "123456789(FirstName string)
example: 123456789TurboTurkey
How can I clean up the length of the string and get in the SSN properly

There is no enough space to store 9 digit in SSN. If you want to store 9 digit in it, its size should be 10 (9 digit + NULL). If there is no NULL charactor, it will read near by locations too..

Related

C Input scanf() confusion

I want to use scanf() to read the input string.
If the input of printf("Enter start word: "); is the symbol #, it will not execute the next printf("Enter end word: "); command, and if the input is a word, then it will execute the next command. But I don't know how to determine whether the input is a symbol or a word.
Whatever I input, it still executes printf("Enter end word: ");
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#define MAX_WORD_LENGTH 32
#define FORMAT_STRING "%31s"
#define VERY_HIGH_VALUE 999999
char **InputWords(int *n, char *start, char *end) {
printf("Enter a number: ");
scanf("%d", n); // the number of the input words
char **words = malloc(sizeof(char *) * *n);
assert(words != NULL);
for (int i = 0; i < *n; i++) {
// allocate memory for the length of each input word
words[i] = malloc(sizeof(char) * MAX_WORD_LENGTH);
assert(words[i] != NULL);
printf("Enter a word: ");
scanf(FORMAT_STRING, words[i]);
}
printf("Enter start word: ");
if (scanf("%s", start) == 1) {
printf("Enter end word: ");
scanf("%s", end);
};
printf("\n");
printf("%d, %s, %s", *n, start, end);
return words;
}
int main(void) {
int n;
char start, end; //the start/end word, which is not necessary in stage 1-4
char **words = InputWords(&n, &start, &end); //create an array to store all input words
return 0;
}
Moreover, when I add the code printf("%d", n); at the end of the function, the value of n becomes 0, although my input n is other number.
When I add printf("%d, %s, %s", *n, start, end); at the last, the output shows
Enter a number: 3
Enter a word: bad
Enter a word: ban
Enter a word: dad
Enter start word: bad
Enter end word: ban
110, an, ban
But in my input, the n = 3, start = ban and end = ban
There are multiple problems in the code:
you pass the addresses of single char variables to InputWords instead of arrays of sufficient length. Reading a string into single char variables causes undefined behavior because scanf() will store at least 2 bytes into the destination array.
you should always specify the maximum number of characters to store into the destination arrays for scanf("%s", ...)
to prevent reading the end word you can simply test if the word read for start starts with a #:
*end = *start = '\0';
if (scanf("%31s", start) == 1 && *start != '#') {
printf("Enter end word: ");
scanf("%31s", end);
}
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
#define MAX_WORD_LENGTH 31
#define FORMAT_STRING "%31s"
char **InputWords(int *np, char *start, char *end) {
int n = 0;
*np = 0;
*start = *end = '\0';
printf("Enter a number: ");
if (scanf("%d", &n) != 1) // the number of the input words
return NULL;
char **words = calloc(sizeof(char *), n);
assert(words != NULL);
for (int i = 0; i < n; i++) {
// allocate memory for the length of each input word
words[i] = calloc(sizeof(char), MAX_WORD_LENGTH + 1);
assert(words[i] != NULL);
printf("Enter a word: ");
if (scanf(FORMAT_STRING, words[i]) != 1) {
/* invalid input or premature end of file */
while (i --> 0) {
free(words[i]);
}
free(words);
return NULL;
}
}
printf("Enter start word: ");
if (scanf(FORMAT_STRING, start) == 1 && *start != '#') {
printf("Enter end word: ");
scanf(FORMAT_STRING, end);
}
printf("\n");
printf("%d, %s, %s\n", n, start, end);
*np = n;
return words;
}
int main() {
int n;
char start[MAX_WORD_LENGTH + 1]; // the start word
char end[MAX_WORD_LENGTH + 1]; // the end word, which is not necessary in stage 1-4
char **words = InputWords(&n, start, end); //create an array to store all input words
return 0;
}
Try this and tell me what doesn't work now:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#define FORMAT_STRING "%31s"
#define MAX_WORD_LENGTH 32
char **InputWords(int *n, char *start, char *end) {
printf("Enter a number: ");
scanf("%d", n); // the number of the input words
char **words = malloc((*n) * sizeof(*words));
assert(words);
for (int i = 0; i < *n; i++) {
// allocate memory for the length of each input word
words[i] = malloc(MAX_WORD_LENGTH);
assert(words[i]);
printf("Enter a word: ");
scanf(FORMAT_STRING, words[i]);
}
printf("Enter start word: ");
if (scanf(FORMAT_STRING, start) == 1) {
printf("Enter end word: ");
scanf(FORMAT_STRING, end);
};
printf("\n%d, %s, %s", *n, start, end);
return words;
}
int main(void){
int n;
char start[MAX_WORD_LENGTH];
char end[MAX_WORD_LENGTH];
char **words = InputWords(&n, start, end); //create an array to store all input words
// silence unused variables
(void) n;
(void) start;
(void) end;
return 0;
}

C programming call by reference pointer function to delete a member of a structure

This is for schoolwork and the question is asking to make a programme like a student database where I am able to input, print and remove students from the structure s using pointers function. However I am unable to delete the student records as something weird happens. The target student gets deleted but the rest of the students records(names only) are shifted, with only the first character being correct. Please help!
#include <stdio.h>
#include <string.h>
#define SIZE 50
typedef struct {
int id;
char name[50];
} Student;
void inputStud(Student *s, int size);
void printStud(Student *s, int size);
int removeStud(Student *s, int *size, char *target);
int main()
{
Student s[SIZE];
int size=0, choice;
char target[80], *p;
int result;
printf("Select one of the following options: \n");
printf("1: inputStud()\n");
printf("2: removeStud()\n");
printf("3: printStud()\n");
printf("4: exit()\n");
do {
printf("Enter your choice: \n");
scanf("%d", &choice);
switch (choice) {
case 1:
printf("Enter size: \n");
scanf("%d", &size);
printf("Enter %d students: \n", size);
inputStud(s, size);
break;
case 2:
printf("Enter name to be removed: \n");
scanf("\n");
fgets(target, 80, stdin);
if (p=strchr(target,'\n')) *p = '\0';
printf("removeStud(): ");
result = removeStud(s, &size, target);
if (result == 0)
printf("Successfully removed\n");
else if (result == 1)
printf("Array is empty\n");
else if (result == 2)
printf("The target does not exist\n");
else
printf("An error has occurred\n");
break;
case 3:
printStud(s, size);
break;
}
} while (choice < 4);
return 0;
}
void inputStud(Student *s, int size)
{
int i=0;
char *p,dummy[50];
while (i<size) {
printf("Student ID: \n");
scanf("%d",&((s+i)->id));
printf("Student Name: \n");
scanf("\n");
fgets((s+i)->name, 50,stdin);
if (p=strchr((s+i)->name,'\n')) *p = '\0';
i++;
}
}
void printStud(Student *s, int size)
{
int i;
printf("The current student list: \n");
if (size==0) printf("Empty array\n");
else {
for (i=0; i<size; i++) {
printf("Student ID: %d ",(s+i)->id);
printf("Student Name: %s\n",(s+i)->name);
}
}
}
int removeStud(Student *s, int *size, char *target)
{
int i,j,k;
if (*size==0) return 1;
for (i=0;i<*size;i++) {
if (strcmp(((s+i)->name),target)==0) {
--*size;
for (j=i; j<=*size; j++) {
k = j + 1;
*((s+j)->name) = *((s+k)->name);
(s+j)->id = (s+j+1)->id;
if ((s+j+1)->id=='\0') (s+j)->id = '\0';
}
return 0;
}
}
return 2;
}
you were almost there.
The problem is at line 97: *((s+j)->name) = *((s+k)->name);
To make it work, this instruction should be substituted with:
strcpy((s+j)->name, (s+k)->name);
Why:
you are coping with char arrays, so doing *((s+j)->name) = *((s+k)->name) means: "put the value of the first char of s+k->name into s+j->name first char".
Instead, you want to copy the whole name of s+k into the s+j name.
on how to use strcpy you can take a look here

Scanf doesnt take more than 4 characters in a const char array - C

I have a really weird bug. If I write a name which contains more than 4 characters, the printf will only output the first 4 characters.
Important note: I am not allowed to use any other library than stdio.h and I am not allowed to use anything else than scanf for input and printf for output. Moreover I am not allowed to modify the paramater list of the functions and I have to use const char. The code runs on putty via ssh on a unix system.
My code and the input/output are below. In addition, the while loop has a bug too ._.
#include <stdio.h>
int searchCharacters(const char*, char);
int getLength(const char*);
int main() {
char yesNo;
int end = 0;
const char name[] = {""};
printf("please enter a name: ");
scanf("%s", name);
int length = getLength(name);
printf("\n%s has a length of %i", name, length);
fflush(stdin);
while(end != 1) {
printf("\n\nWould you like to search a character in %s (y / n)?", name);
scanf(" %c", &yesNo);
switch(yesNo) {
case 'y':
printf("\nPlease enter a character: ");
char searchingCharacter;
scanf("%c", &searchingCharacter);
int numberOfCharacters = searchCharacter(name, searchingCharacter);
printf("\nThe letter %c is %i-times", searchingCharacter, numberOfCharacters);
break;
case 'n':
printf("\nGood bye!");
end++;
break;
}
}
return 0;
}
int searchCharacter(const char s[], char c) {
int numberOfIterations = getLength(s);
int numberOfCharacters = 0;
int i;
for (int i = 0; i < numberOfIterations; i++) {
if (s[i] == c) {
numberOfCharacters++;
}
}
return numberOfCharacters;
}
int getLength(const char s[]) {
int i = 0;
while(s[i++]);
return (i - 1);
}
Input/Output:
please enter a name: abcdefg
abcd has a length of 7 characters.
Would you like to search a character in abcd (y / n)? y
<-------------- AUTOMATIC/BUG WHILE LOOP --------------------------->
Please enter a character:
The letter
is 0-times.
</--------------AUTOMATIC/BUG WHILE LOOP---------------------------->
Would you like to search a character in abcd (y / n)? n
Good bye!
So, here is a possible answer:
"Change const char name[] to char name[100]" (from #kaylum)
"Change scanf("%c", &searchingCharacter) --> scanf(" %c", %searchingCharacters) to consume new line in input stream" (from #user3121023)
Here is the full code:
#include <stdio.h>
int searchCharacters(const char*, char);
int getLength(const char*);
int main() {
char yesNo;
int end = 0;
char name[100]; <-- Changed -->
printf("please enter a name: ");
scanf("%99s", name);
fflush(stdin);
int length = getLength(name);
printf("\n%s has a length of %i", name, length);
while(end != 1) {
printf("\n\nWould you like to search a character in %s (y / n)?", name);
scanf("%c", &yesNo); <-- Changed -->
switch(yesNo) {
case 'y':
printf("\nPlease enter a character: ");
char searchingCharacter;
scanf(" %c", &searchingCharacter); <-- Changed -->
int numberOfCharacters = searchCharacter(name, searchingCharacter);
printf("\nThe letter %c is %i-times", searchingCharacter,
numberOfCharacters);
break;
case 'n':
printf("\nGood bye!");
end++;
break;
}
}
return 0;
}
int searchCharacter(const char s[], char c) {
int numberOfIterations = getLength(s);
int numberOfCharacters = 0;
int i;
for (int i = 0; i < numberOfIterations; i++) {
if (s[i] == c) {
numberOfCharacters++;
}
}
return numberOfCharacters;
}
int getLength(const char s[]) {
int i = 0;
while(s[i++]);
return (i - 1);
}
Input/Output:
please enter a name: abcdefg
abcdefg has a length of 7 characters. <-- Working/Changed -->
Would you like to search a character in abcd (y / n)? y
Please enter a character: a <-- Working/Changed -->
The letter a is 1-times. <-- Working/Changed -->
Would you like to search a character in abcdefg (y / n)? n
Good bye!

Can't read array of structure in C

I am trying to read members of an object like in the code below.
The issue is that the code can't read the second member (car[i].model) in the array and the third one (car[i].price), only the first one (car[i].manufacturer).
#include <stdio.h>
#include <conio.h>
struct machine
{
int price;
char manufacturer[30];
char model[30];
};
int main()
{
int i = 0, n;
printf("Introduce number of cars: ");
scanf_s("%d", &n);
struct machine car[100];
for (i = 0; i < n; i++)
{
printf("Data of the car nr. %d:\n", i+1);
printf("Manufacturer: ");
scanf_s("%s", car[i].manufacturer);
printf("Model: ");
scanf_s("%s", car[i].model); printf("\n");
printf("Price: ");
scanf_s("%d", &car[i].price); printf("\n");
}
for (i = 0; i < n; i++)
{
printf("Data of the car nr. %d:\n", i + 1);
printf("Manufacturer: %s\n", car[i].manufacturer);
printf("Manufacturer: %s\n", car[i].manufacturer);
printf("Model: %s\n", car[i].model);
printf("Price %d\n", car[i].price);
}
_getch();
}
scanf_s requires the buffer size to be specified for input parameters with format %s. The buffer size includes the terminating null. Adapt your code like this:
struct machine
{
int price;
char manufacturer[30];
char model[30];
};
struct machine car[100];
....
scanf_s("%s", car[i].manufacturer, 30 );
// ^^ buffer size
....
scanf_s("%s", car[i].model, 30 );
// ^^ buffer size
....
scanf_s("%d", &car[i].price); // no buffer size

Program is terminating without recognizing scanf

I don't know why my program terminates before confirmStats(); is called. I included everything related in main() in case the issue is ocurring somewhere else in my program.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int str, intel, charis;
int totalPts =5;
/* Returns a number.
User must input an integer.
*/
int getNumber(int number){
while(scanf("%d", &number) != 1){
printf("You did not enter a valid number\n");
scanf("%*s");
}
return number;
}
/* Individual stat points */
int stat(int number){
number = getNumber(number);
while(number > totalPts){
printf("You only have %d stat points left\n", totalPts);
printf("Enter a number less than or equal to %d:\t", totalPts);
number = getNumber(number);
}
totalPts -= number;
printf("Points remaining:\t%d\n", totalPts);
return number;
}
/* Player stat points */
void getStats(){
printf("You're alotted %d stat points to spend in Strength, Intellect, and Charisma\n", totalPts);
printf("Intellect:\t");
intel = stat(intel);
printf("Strength:\t");
str = stat(str);
printf("Charisma:\t");
charis = stat(charis);
printf("\nIntellect: %d\t Strength: %d\t Charisma: %d\n", intel, str, charis);
}
void confirmStats(){
char ans;
scanf("%c", &ans);
while(ans == 'n'){
str = 0;
intel = 0;
charis = 0;
getStats();
printf("Are these correct?:\ty/n: ");
scanf("%c", &ans);
}
}
void main(){
printf("\nSafe choice...");
printf("\n");
printf("Alright, how old are you?\n");
// int age, str, intel, charis;
int age;
// int totalPts = 5;
age = getNumber(age);
getStats();
printf("Are these correct? ");
printf("\n");
printf("y/n:\t");
printf("\n");
confirmStats();
}
The problem is that scanf("%c", &ans); scans the newline character left over by the previous scanf.
The fix is easy. Simply add a space before %c in the two scanfs in confirmStats. The space is a whitespace character and a whitespace character in the format string of scanf tells scanf to scan any number of whitespace characters, if any, until the first non-whitespace character.
Improved code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int str, intel, charis;
int totalPts = 5;
/*
Returns a number.
User must input an integer.
*/
int getNumber(){
int number;
while(scanf("%d", &number) != 1){
printf("You did not enter a valid number\n");
scanf("%*s");
}
return number;
}
/* Individual stat points */
int stat(){
int number;
number = getNumber();
while(number > totalPts){
printf("You only have %d stat points left\n", totalPts);
printf("Enter a number less than or equal to %d:\t", totalPts);
number = getNumber();
}
totalPts -= number;
printf("Points remaining:\t%d\n", totalPts);
return number;
}
/* Player stat points */
void getStats(){
printf("You're alotted %d stat points to spend in Strength, Intellect, and Charisma\n", totalPts);
printf("Intellect:\t");
intel = stat();
printf("Strength:\t");
str = stat();
printf("Charisma:\t");
charis = stat();
printf("\nIntellect: %d\t Strength: %d\t Charisma: %d\n", intel, str, charis);
}
void confirmStats(){
char ans;
scanf(" %c", &ans);
while(ans == 'n'){
str = 0;
intel = 0;
charis = 0;
getStats();
printf("Are these correct?:\ty/n: ");
scanf(" %c", &ans);
}
}
int main(void){
printf("\nSafe choice...");
printf("\n");
printf("Alright, how old are you?\n");
age = getNumber();
getStats();
printf("Are these correct? ");
printf("\n");
printf("y/n:\t");
printf("\n");
confirmStats();
return 0;
}
int getNumber(int number){
int ok = 0;
while (!ok){
if(scanf("%d", &number) != 1){
printf("You did not enter a valid number\n");
while(getchar()!='\n');
}
else {
getchar();
ok=1;
}
}
return number;
}
Sir ,do u have checked the syntax is scant("%d",&variable);
Not. scant("%d",variable);

Resources