malloc/struct pointer array seg fault - c

I have this code below, includes and other functions which are called in main are correct. But when I am trying to malloc the words[counter]->input_str, I get a segmentation fault all the time. I don't know what to do.
struct copy {
char *input_str;
char *create_word;
};
int main(int argc, char *argv[]) {
static struct copy *words[ARRAY_SIZE];
char format_str[20];
char word_str[STR_SIZE];
int how_many;
int counter = 0;
char answer;
do{
sprintf(format_str," %%%ds",STR_SIZE - 1);
printf("Enter string: ");
scanf(format_str,word_str);
words[counter]->input_str = (char *)malloc((strlen(word_str) + 1)*sizeof(char));
if(words[counter]->input_str == NULL) {
printf("memory problem\n");
exit(-1);
}
words[counter]->input_str = word_str;
printf("Enter integer: ");
scanf(" %d",&how_many);
words[counter]->create_word = duplicate(word_str,how_many);
counter++;
if(words[counter - 1] == NULL) {
printf("error\n");
exit(-1);
}
print(words,counter);
do{
printf("More (y/n)? ");
scanf(" %c",&answer);
}while(answer != 'y' && answer != 'n');
}while(counter < ARRAY_SIZE && answer == 'y');
clean(words,counter);
return(0);
}

Here are two versions of your code,one using struct copy *words[ARRAY_SIZE]; at the top of main(), the other using struct copy words[ARRAY_SIZE]; (which therefore does less memory allocation).
Array of pointers
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct copy
{
char *input_str;
char *create_word;
};
enum { ARRAY_SIZE = 20, STR_SIZE = 30 };
extern char *duplicate(const char *str, int number);
extern void print(struct copy **words, int number);
extern void clean(struct copy **words, int number);
int main(void)
{
struct copy *words[ARRAY_SIZE];
char format_str[20];
char word_str[STR_SIZE];
int how_many;
int counter = 0;
char answer;
sprintf(format_str, " %%%ds", STR_SIZE - 1);
do
{
printf("Enter string: ");
if (scanf(format_str, word_str) != 1)
break;
printf("Enter integer: ");
if (scanf(" %d", &how_many) != 1 || how_many < 0 || how_many > 999)
break;
words[counter] = malloc(sizeof(*words[counter]));
words[counter]->input_str = (char *)malloc((strlen(word_str) + 1) * sizeof(char));
if (words[counter]->input_str == NULL)
{
fprintf(stderr, "memory problem\n");
exit(-1);
}
strcpy(words[counter]->input_str, word_str);
words[counter]->create_word = duplicate(word_str, how_many);
// Superfluous because duplicate exits if there is an allocation error
if (words[counter]->create_word == NULL)
{
fprintf(stderr, "error\n");
exit(-1);
}
counter++;
print(words, counter);
do
{
printf("More (y/n)? ");
if (scanf(" %c", &answer) != 1)
{
answer = 'n';
break;
}
} while (answer != 'y' && answer != 'n');
} while (counter < ARRAY_SIZE && answer == 'y');
clean(words, counter);
return(0);
}
void print(struct copy **words, int number)
{
printf("Words (%d):\n", number);
for (int i = 0; i < number; i++)
printf("[%s] => [%s]\n", words[i]->input_str, words[i]->create_word);
}
char *duplicate(const char *str, int number)
{
int len1 = strlen(str);
int len2 = number * len1 + 1;
char *space = malloc(len2);
if (space == NULL)
{
fprintf(stderr, "memory allocation failed for %d bytes\n", len2);
exit(-1);
}
for (int i = 0; i < number; i++)
strcpy(&space[i * len1], str);
space[len2 - 1] = '\0'; // In case number == 0
return space;
}
void clean(struct copy **words, int number)
{
for (int i = 0; i < number; i++)
{
free(words[i]->input_str);
free(words[i]->create_word);
free(words[i]);
words[i] = NULL;
}
}
Array of structures
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct copy
{
char *input_str;
char *create_word;
};
enum { ARRAY_SIZE = 20, STR_SIZE = 30 };
extern char *duplicate(const char *str, int number);
extern void print(struct copy *words, int number);
extern void clean(struct copy *words, int number);
int main(void)
{
struct copy words[ARRAY_SIZE];
char format_str[20];
char word_str[STR_SIZE];
int how_many;
int counter = 0;
char answer;
sprintf(format_str, " %%%ds", STR_SIZE - 1);
do
{
printf("Enter string: ");
if (scanf(format_str, word_str) != 1)
break;
words[counter].input_str = (char *)malloc((strlen(word_str) + 1) * sizeof(char));
if (words[counter].input_str == NULL)
{
fprintf(stderr, "memory problem\n");
exit(-1);
}
strcpy(words[counter].input_str, word_str);
printf("Enter integer: ");
if (scanf(" %d", &how_many) != 1 || how_many < 0 || how_many > 999)
break;
words[counter].create_word = duplicate(word_str, how_many);
// Superfluous because duplicate exits if there is an allocation error
if (words[counter].create_word == NULL)
{
fprintf(stderr, "error\n");
exit(-1);
}
counter++;
print(words, counter);
do
{
printf("More (y/n)? ");
if (scanf(" %c", &answer) != 1)
{
answer = 'n';
break;
}
} while (answer != 'y' && answer != 'n');
} while (counter < ARRAY_SIZE && answer == 'y');
clean(words, counter);
return(0);
}
void print(struct copy *words, int number)
{
printf("Words (%d):\n", number);
for (int i = 0; i < number; i++)
printf("[%s] => [%s]\n", words[i].input_str, words[i].create_word);
}
char *duplicate(const char *str, int number)
{
int len1 = strlen(str);
int len2 = number * len1 + 1;
char *space = malloc(len2);
if (space == NULL)
{
fprintf(stderr, "memory allocation failed for %d bytes\n", len2);
exit(-1);
}
for (int i = 0; i < number; i++)
strcpy(&space[i * len1], str);
space[len2 - 1] = '\0'; // In case number == 0
return space;
}
void clean(struct copy *words, int number)
{
for (int i = 0; i < number; i++)
{
free(words[i].input_str);
free(words[i].create_word);
words[i].input_str = words[i].create_word = NULL;
}
}
Sample output:
Enter string: abc
Enter integer: 1
Words (1):
[abc] => [abc]
More (y/n)? y
Enter string: def
Enter integer: 2
Words (2):
[abc] => [abc]
[def] => [defdef]
More (y/n)? y
Enter string: absolute-twaddle
Enter integer: 10
Words (3):
[abc] => [abc]
[def] => [defdef]
[absolute-twaddle] => [absolute-twaddleabsolute-twaddleabsolute-twaddleabsolute-twaddleabsolute-twaddleabsolute-twaddleabsolute-twaddleabsolute-twaddleabsolute-twaddleabsolute-twaddle]
More (y/n)? y
Enter string: ABCDEFGHIJKLMNOPQRSTUVWXYZ
Enter integer: 0
Words (4):
[abc] => [abc]
[def] => [defdef]
[absolute-twaddle] => [absolute-twaddleabsolute-twaddleabsolute-twaddleabsolute-twaddleabsolute-twaddleabsolute-twaddleabsolute-twaddleabsolute-twaddleabsolute-twaddleabsolute-twaddle]
[ABCDEFGHIJKLMNOPQRSTUVWXYZ] => []
More (y/n)? n
(Either program gives the same output for the same input. Both run clean under Valgrind — a site which still does not support https connections.)

Related

Why my fputs doesn't work when the file already contains anything?

I try to add a new line to the already existing file, which already consists some text. I found out that when the file contains something, the program stops working after fputs(stringToAdd, myFile); in function void Save(struct SEED arrayToSave[], int size). However, when I try to write in an empty file, everything works properly. Can you guys please help me?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int numberOfItems = 0;
char path[] = "Catalogue.txt";
char text[1000000];
struct SEED {
int index;
char type[30];
char name[60];
float mass;
float price;
};
void GetText() {
FILE* catalogueFile;
char ch; // temporary char
int counter = 0;
catalogueFile = fopen(path, "r");
while((ch = fgetc(catalogueFile)) != EOF ) {
text[counter] = ch;
counter++;
}
fclose(catalogueFile);
}
void CalculateNumberOfItems() {
for(int i = 0; i < strlen(text); i++) {
if(text[i] == '\n') numberOfItems++;
}
}
struct SEED* GetArrayOfStructs() {
GetText();
CalculateNumberOfItems();
FILE* catalogueFile;
int counter = 0;
char* arrayOfSubstrings[numberOfItems];
struct SEED* arrayOfStructs = malloc(numberOfItems * sizeof(arrayOfStructs));
struct SEED* arrayOfStructsPointer = arrayOfStructs;
char* token = strtok(text, "\n");
while( token != NULL ) {
arrayOfSubstrings[counter] = token;
token = strtok(NULL, "\n");
counter++;
}
for(int i = 0; i < numberOfItems; i++) {
struct SEED tempStruct;
sscanf(arrayOfSubstrings[i], "%d %s %s %f %f", &tempStruct.index, tempStruct.type, tempStruct.name, &tempStruct.mass, &tempStruct.price);
arrayOfStructs[i] = tempStruct;
}
return arrayOfStructsPointer;
}
void Save(struct SEED arrayToSave[], int size) {
FILE* myFile = fopen("Catalogue.txt", "w");
char fullString[1000000];
for(int i = 0; i < size; i++) {
struct SEED currentStruct = arrayToSave[i];
char stringToAdd[1000];
sprintf(stringToAdd, "%d %s %s %f %f\n", currentStruct.index, currentStruct.type, currentStruct.name, currentStruct.mass, currentStruct.price);
strcat(fullString, stringToAdd);
}
printf("%s\n", fullString);
fputs(fullString, myFile);
fclose(myFile);
}
void AddNew() {
struct SEED* oldArrayOfStructs = GetArrayOfStructs(path);
struct SEED newArrayOfStructs[numberOfItems + 1];
struct SEED newStruct;
int newIndex = numberOfItems + 1;
char newType[30], newName[60];
float newMass, newPrice;
char tempChar[200];
printf("Input type, name, mass and price\nof the new seed whith spaces: ");
fgets(tempChar, 200, stdin);
fgets(tempChar, 200, stdin);
sscanf(tempChar, "%s %s %f %f\\n", newType, newName, &newMass, &newPrice);
newStruct.index = newIndex;
strcpy(newStruct.type, newType);
strcpy(newStruct.name, newName);
newStruct.mass = newMass;
newStruct.price = newPrice;
printf("%d\n", numberOfItems);
for(int i = 0; i < numberOfItems; i++) {
newArrayOfStructs[i] = oldArrayOfStructs[i];
}
newArrayOfStructs[numberOfItems] = newStruct;
Save(newArrayOfStructs, numberOfItems + 1);
printf("\n");
}
void UserInput() {
char choice;
int choiceInt, a = 1;
printf("Add new item - print 1\n");
printf("\n");
printf("Input your choice: ");
choice = getchar();
choiceInt = choice - '0';
printf("\n");
switch(choiceInt) {
case 1:
AddNew();
break;
default:
printf("Bye!\n");
break;
}
}
int main() {
UserInput();
return 0;
}
At least these problems:
Allocation too small
Code incorrectly allocates for an array of pointers.
// struct SEED* arrayOfStructs = malloc(numberOfItems * sizeof(arrayOfStructs));
struct SEED* arrayOfStructs = malloc(numberOfItems * sizeof arrayOfStructs[0]);
char too small to distinguish 257 different responses from fgetc()
// char ch; // temporary char
int ch;
...
while((ch = fgetc(catalogueFile)) != EOF ) {
Potential buffer overrun
Use a width.
No point scanning for 2 characters \ and n with "\\n".
// sscanf(tempChar, "%s %s %f %f\\n", newType, newName, &newMass, &newPrice);
sscanf(tempChar, "%29s %59s %f %f", newType, newName, &newMass, &newPrice);
Best to test sscanf() result too.
if (sscanf(tempChar, "%29s %59s %f %f", newType, newName, &newMass, &newPrice) != 4) {
TBD_error_code();
}
Overflow risk
// while((ch = fgetc(catalogueFile)) != EOF ) {
while(counter < (sizeof text - 1) && (ch = fgetc(catalogueFile)) != EOF ) {
text[counter] = ch;
Maybe overflow risk
// sprintf(stringToAdd, "%d %s %s %f %f\n",
snprintf(stringToAdd, sizeof stringToAdd, "%d %s %s %f %f\n",

Reallocating my Memory doesnt work properly but i dont know what im doing wrong. Any idea?

code: (at //right here is the line that doesnt work)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
void insert(int size, char *arr);
void swap(char *arr, int pos1, int pos2);
void printList(int size, char *arr);
int main()
{
int size = 0;
do
{
printf("Put in size of the list (Range[1;2^16-1]): ");
scanf(" %d", &size);
if (size < 0)
printf("Put in a correct length!\n");
} while (size <= 0);
printf("Put in ur List: ");
char buffer[size];
int errFlag;
do
{
errFlag = 1;
while (fgets(buffer, size + 2, stdin))
{
}
for (int i = 0; i < size; i++)
if (!isdigit(buffer[i]))
errFlag = 0;
if (errFlag == 0)
printf("Input failed try again:");
} while (errFlag == 0);
char *list = malloc(size*sizeof(char));
strcpy(list, buffer);
insert(size, list);
printList(size, list);
int input = 0;
do
{
printf("\nDo u want to add another element(0) or a list(1)? If u want to stop type (2): ");
scanf(" %d", &input);
if (input != 0 && input != 1 && input != 2)
printf("\nInput failed try again: ");
else if (input == 1)
{
int tempElem = 0;
printf("Input ur element: ");
scanf(" %d", &tempElem);
size++;
printf("%d", tempElem);
list = (char *)realloc(list, size + 1); //right here
list[size-1]=tempElem;
printf("New ");
insert(size, list);
printList(size, list);
}
} while (input != 0);
return 0;
}
void insert(int size, char *arr)
{
for (int i = 1; i < size; i++)
for (int j = i - 1; j >= 0; j--)
if (arr[j] > arr[j + 1])
swap(arr, j, j + 1);
else
j = 0;
}
void swap(char *arr, int pos1, int pos2)
{
char temp = arr[pos1];
arr[pos1] = arr[pos2];
arr[pos2] = temp;
}
void printList(int size, char *arr)
{
printf("ArrayList: ");
for (int i = 0; i < size; i++)
{
printf("[");
printf("%d", arr[i]-48);
printf("] ");
}
}
My code works properly until the reallocation, but i dont get an error. The programm just stops (VScode). I did some research but didnt find any solution.
Output:
Put in size of the list (Range[1;2^16-1]): 3
Put in ur List: 123
^Z (my input to stop f gets)
ArrayList: [1] [2] [3]
Do u want to add another element(0) or a list(1)? If u want to stop type (2): 1
Input ur element: 3
3
Then it stops. Normally i would expect: New ArrayList: [1] [2] [3] [4]

C program dynamic memory allocation error, string value issue

I have tried multiple methods for a long time but it didn't work, the output automatically updates all previously entered values for the name.
The find method is not required to be checked, but the first display itself provides invalid output:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int phone;
char *name;
} phonecontact;
phonecontact *create(phonecontact *p, int phone, char name[], int i) {
(p+i)->name = (char *)calloc(10, sizeof(char));
(p+i)->name = name;
(p+i)->phone = phone;
printf("\n%s\n", (p+i)->name);
return p;
}
void display(phonecontact *p, int i) {
printf("Name : %s , Phone number : %d\n", p[i].name, p[i].phone);
}
int find(phonecontact *p, char name[], int *num) {
int phone, i = 0;
for (i = 0; i < *num; i++) {
if (strcmp(p[i].name, name) == 1)
display(p, i);
return 1;
}
p = (phonecontact *)realloc(p, ++(*num) * sizeof(phonecontact));
printf("Enter phone number for entered person : ");
scanf("%d", &phone);
p = create(p, phone, name, i + 1);
return 0;
}
int main() {
int num, phone;
char name[30];
printf("Enter number of contacts : ");
scanf("%d", &num);
phonecontact *p;
p = (phonecontact *)calloc(num, sizeof(phonecontact));
for (int i = 0; i < num; i++) {
printf("Enter name : ");
scanf("%s", name);
printf("Enter phone number : ");
scanf("%d", &phone);
p = create(p, phone, name, i);
}
printf("\n%s\n", (p)->name);
printf("\n%s\n", (p + 1)->name);
printf("\n%s\n", (p + 2)->name);
for (int i = 0; i < num; i++) {
display(p, i);
}
printf("Enter name of contact : ");
scanf("%s", &name);
find(p,name, &num);
}
There are many problems in the code:
For each contact to have its own name string, you must allocate a copy of the create() string argument:
phonecontact *create(phonecontact *p, int phone, const char *name, int i) {
p[i].name = strdup(name);
p[i].phone = phone;
printf("\n%s\n", p[i].name);
return p;
}
the function strcmp() returns 0 when the strings compare equal, a negative value if the first argument compares less than the second in lexicographical order and a value greater than zero otherwise.
You should use if (strcmp(p[i].name, name) == 0) and return 1 only if the strings compare equal.
It is confusing for a function named find() to append a new entry in the array.
The array reallocated by find() is not passed back to the caller, and the previous pointer may have become invalid, causing undefined behavior.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int phone;
char *name;
} phonecontact;
int flush_input(void) {
int c;
while ((c = getchar()) != EOF && c != '\n')
continue;
return c;
}
void init_contact(phonecontact *p, int phone, const char *name) {
p->name = strdup(name);
p->phone = phone;
}
void display_contact(const phonecontact *p) {
printf("Name: %s, Phone number: %d\n", p->name, p->phone);
}
int add_contact(phonecontact **pp, int *pnum, const char *name) {
int phone;
int num = *pnum;
phonecontact *p = *pp;
for (int i = 0; i < num; i++) {
if (strcmp(p[i].name, name) == 1) {
display_contact(&p[i]);
return 1;
}
}
/* reallocate the contact array */
p = (phonecontact *)realloc(p, (num + 1) * sizeof(*p));
if (p == NULL) {
printf("cannot reallocate contact array\n");
return -1;
}
printf("Enter phone number for entered person: ");
while (scanf("%d", &phone) != 1) {
printf("Invalid input. Try again: ");
if (flush_input() == EOF)
return -1;
}
init_contact(&p[num], phone, name);
*pnum = num + 1;
*pp = p;
return 0;
}
int main() {
int num, phone;
char name[30];
printf("Enter number of contacts : ");
if (scanf("%d", &num) != 1 || num < 0) {
fprintf(stderr, "invalid input\n");
return 1;
}
phonecontact *p = calloc(num, sizeof(*p));
if (p == NULL) {
fprintf(stderr, "memory allocation error\n");
return 1;
}
for (int i = 0; i < num; i++) {
printf("Enter name: ");
if (scanf(" %29[^\n]", name) != 1) {
fprintf(stderr, "invalid input\n");
return 1;
}
printf("Enter phone number: ");
if (scanf("%d", &phone) != 1)
fprintf(stderr, "invalid input\n");
return 1;
}
init_contact(&p[i], phone, name);
}
for (int i = 0; i < num; i++) {
display_contact(&p[i]);
}
printf("Enter name of contact: ");
if (scanf(" %29[^\n]", &name) == 1)
add_contact(&p, *num, name);
return 0;
}

swap strings function in c with pointers

When I try to swap between strings in the function Update_student it doesn't make it. Why?
#include <stdio.h>
#include <string.h>
#define SIZE 1
struct student {
int id_number;
char name[50];
char sex[6];
int quiz_score[2];
int total_score;
};
void Add_Student_Records(struct student *pupil) {
printf("ID:");
scanf("%d", &pupil->id_number);
printf("Name: ");
scanf("%s", &pupil->name);
printf("Sex :");
scanf("%s", &pupil->sex);
for (int i = 0; i < 2; i++) {
printf("Quit score %d:", i + 1);
scanf("%d", &pupil->quiz_score[i]);
}
pupil->total_score = pupil->quiz_score[0] + pupil->quiz_score[1];
return;
}
void Add_Students(struct student *students) {
for (int i = 0; i < SIZE; i++) {
printf("Student %d:\n", i + 1);
Add_Student_Records(students);
}
return;
}
void Print_Students(struct student *students) {
for (int i = 0; i < SIZE; i++) {
printf("Student %d details: \n", i + 1);
printf("ID:%d\n", students->id_number);
printf("Name:%s\n", students->name);
printf("Sex:%s\n", students->sex);
for (int i = 0; i < 2; i++) {
printf("Quit score %d:\n", students->quiz_score[i]);
}
printf("Total score: %d\n", students->total_score);
students++;
}
return;
}
void Replace_Strings(char **old_string, char **new_string) {
*old_string = *new_string;
return;
}
void Update_Student(struct student *students) {
int i = 0;
char name[50], new_name[50], cur_name[50];
printf("You can update name, and scores.\n");
printf(" current Name: ");
scanf("%s", name);
printf("new name: ");
scanf("%s", &new_name);
while (i < SIZE) {
strcpy(cur_name, students->name);
if (strcmp(cur_name, name) == 0) {
char *ptr_old_stud_name = students->name;
char *ptr_new_stud_name = new_name;
Replace_Strings(&ptr_old_stud_name, &ptr_new_stud_name);
}
i++;
students++;
}
return;
}
int main() {
struct student students[SIZE];
char ch;
/*1.Add student, 2. Print student*/
printf("1.Add student\n2.Print students\n3.Update student\n");
scanf("%c", &ch);
while (ch != 'E') {
if (ch == '1') {
Add_Students(&students[0]);
}
else if (ch == '2') {
Print_Students(&students[0]);
}
else if (ch =='3') {
Update_Student(&students[0]);
}
printf("Another operation:\t");
scanf("%c", &ch);
}
}
Replace_Strings(&ptr_old_stud_name,&ptr_new_stud_name); passes the addresses of ptr_old_stud_name and ptr_new_stud_name to ReplaceStrings.
ptr_old_stud_name and ptr_new_stud_name are local variables. The first is a pointer that has been set to point to students->name. The second is a pointer that has been set to point to new_name.
Replace_Strings changes the first thing it is passed a pointer to to the second thing it is passed a pointer to. So it changes ptr_old_stud_name to have the value of ptr_new_stud_name.
The result is that the local variable ptr_old_stud_name has a new value. This does not change the thing it points to, students->name.
More specifically, ptr_old_stud_name was pointing to the first character of students->name. students->name is an array, and it cannot be altered by changing pointers to it, and its address cannot be changed. To change its contents, you must copy new values into the bytes within it, which you could do by using strcpy to copy bytes into it from new_name.
Your function Update_student is confusing, you should just iterate through the array of students and compare the student's name with cur_name and replace the name when there is a match.
You should also pass the number of students to handle as an argument.
Here is a modified version:
void Update_Student(struct student *students, int count) {
char cur_name[50], new_name[50];
printf("You can update name, and scores.\n");
printf(" current Name: ");
scanf("%49s", cur_name);
printf("new name: ");
scanf("%49s", new_name);
for (int i = 0; i < count; i++) {
if (strcmp(cur_name, students[i].name) == 0) {
strcpy(students[i].name, new_name);
}
}
}
Call from main as Update_Student(students, SIZE);
Note also that you should ignore whitespace when reading the commands by adding a space before the %c:
scanf(" %c", &ch);
Here is a modified version with for multiple students:
#include <stdio.h>
#include <string.h>
#define SIZE 10
struct student {
int id_number;
char name[50];
char sex[6];
int quiz_score[2];
int total_score;
};
int Add_Student_Records(struct student *pupil) {
printf("ID:");
if (scanf("%d", &pupil->id_number) != 1)
return 0;
printf("Name: ");
if (scanf("%49s", pupil->name) != 1)
return 0;
printf("Sex :");
if (scanf("%1s", pupil->sex) != 1)
return 0;
for (int i = 0; i < 2; i++) {
printf("Quiz score %d:", i + 1);
if (scanf("%d", &pupil->quiz_score[i]) != 1)
return 0;
}
pupil->total_score = pupil->quiz_score[0] + pupil->quiz_score[1];
return 1;
}
int Add_Students(struct student *students, int count) {
int i;
for (int i = 0; i < count; i++) {
printf("Student %d:\n", i + 1);
if (Add_Student_Records(students + i) == 0)
break;
}
return i;
}
void Print_Students(struct student *students, int count) {
for (int i = 0; i < count; i++) {
printf("Student %d details: \n", i + 1);
printf("ID:%d\n", students->id_number);
printf("Name:%s\n", students->name);
printf("Sex:%s\n", students->sex);
for (int i = 0; i < 2; i++) {
printf("Quit score %d:\n", students->quiz_score[i]);
}
printf("Total score: %d\n", students->total_score);
students++;
}
}
void Update_Student(struct student *students, int count) {
char cur_name[50], new_name[50];
printf("You can update name, and scores.\n");
printf(" current Name: ");
if (scanf("%49s", cur_name) != 1)
return;
printf("new name: ");
if (scanf("%49s", new_name) != 1)
return;
for (int i = 0; i < count; i++) {
if (strcmp(cur_name, students[i].name) == 0) {
strcpy(students[i].name, new_name);
}
}
}
int main() {
struct student students[SIZE];
int n = 0;
char ch = 'E';
/* print the menu */
printf("1. Add student\n"
"2. Print students\n"
"3. Update student\n");
scanf(" %c", &ch);
while (ch != 'E') {
if (ch == '1') {
if (n == SIZE) {
printf("student array is full\n");
} else {
/* add more students */
n += Add_Students(&students[n], SIZE - n);
}
} else
if (ch == '2') {
Print_Students(students, n);
} else
if (ch =='3') {
Update_Student(students, n);
}
scanf("%*[^\n]"); // consume the rest of the pending input line
printf("Another operation:\t");
if (scanf(" %c", &ch) != 1)
break;
}
return 0;
}

Searching an Array of Strings from User Input in C

I've got this homework assignment where we get the user to enter the amount of lines of strings they desire, they then proceed to enter them which gets stored in a 2D Array (thus creating an array of strings). Then a switch case menu will be displayed which should
Search a character entered by the user, returns the amount of times the character occurred in the array
Search a word entered by the user, returns the amount of times the word occurred in the array
Have the user enter a specified word length and return the amount of times words of the specified length occur.
I have a couple problems with my code. The program runs without errors from the compiler. The searchByCharacter function works fine but the searchByWord only returns a value of 0 regardless of any word inputted and nothing happens after I input a number for the searchByLength function. The program freezes after I enter a length once I select the searchByLength function. I've been at this for a while and I don't know where I'm going wrong.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LINE_LENGTH 80
#define MAX_LINES 10
#define WORD_LENGTH 20
void readText(char text[][MAX_LINE_LENGTH], int n)
{
int i;
printf("Enter %d number of lines:\n", n);
for(i = 0; i < n; i++)
{
scanf(" %[^\n]s", text[i]);
}
}
int searchByCharacter(char text[][MAX_LINE_LENGTH], int n, char c)
{
int i, charCount = 0, j = 0;
for(i = 0; i < n; i++)
{
j = 0;
while(text[i][j] != '\0')
{
if(text[i][j] == c)
{
charCount++;
}
j++;
}
}
return charCount;
}
int searchByWord(char text[][MAX_LINE_LENGTH], int n, char * keyword)
{
int i, wordCount = 0;
for(i = 0; i < n; i++)
{
int j = 0;
int lengthOfWord = 0;
char wordCheck[WORD_LENGTH];
char * currentLine = text[i];
while(currentLine[j] != '\0')
{
if (currentLine[j] == ' ' || currentLine[j] == '\n' || currentLine[j] == ',' || currentLine[j] == '.' ||
currentLine[j] == ';')
{
wordCheck[lengthOfWord] = '\0';
int matchingWord = strcmp(wordCheck, keyword);
if(matchingWord == 0)
{
wordCount++;
}
lengthOfWord = 0;
j++;
continue;
}
wordCheck[lengthOfWord] = currentLine[n];
lengthOfWord++;
j++;
}
}
return wordCount;
}
int searchByLength(char text[][MAX_LINE_LENGTH], int n, int wordLen)
{
int i, lengthCount = 0;
for(i = 0; i < n; i++)
{
int lengthOfWord = 0;
int j = 0;
char * currentLine2 = text[i];
while(currentLine2[j] != '\0')
{
if (currentLine2[j] == ' ' || currentLine2[j] == '\n' || currentLine2[j] == ',' || currentLine2[j] == '.' ||
currentLine2[j] == ';')
{
if(lengthOfWord == wordLen)
{
lengthCount++;
}
lengthOfWord = 0;
n++;
continue;
}
lengthOfWord++;
n++;
}
}
return lengthCount;
}
int main(void)
{
char textInput[MAX_LINES][MAX_LINE_LENGTH];
printf("Enter number of lines (<10): ");
int textLines = 0;
scanf("%d", &textLines);
while(textLines < 1 || textLines > 10)
{
printf("Invalid Input.\n");
printf("Enter number of lines (<10): ");
scanf("%d", &textLines);
}
if(textLines >= 1 && textLines <= 10)
{
readText(textInput, textLines);
int menuActive = 1;
while(menuActive)
{
printf("\nText Analysis\n----\n");
printf("1-Search By Character\n2-Search By Word\n3-Search By Length\n0-Quit\nPlease enter a selection: ");
int selection;
scanf("%d", &selection);
switch(selection)
{
case 0:
menuActive = 0;
break;
case 1:
printf("Selected 1\n");
printf("Enter a character to search: ");
char characterSearch;
scanf(" %c", &characterSearch);
int characterwordCount = searchByCharacter(textInput, textLines, characterSearch);
printf("\nNumber of occurence of %c = %d", characterSearch, characterwordCount);
break;
case 2:
printf("Selected 2\n");
printf("Enter a word to search: ");
char wordSearch[MAX_LINE_LENGTH];
scanf(" %s", wordSearch);
int lengthwordCount = searchByWord(textInput, textLines, wordSearch);
printf("\nNumber of occurence of %s = %d", wordSearch, lengthwordCount);
break;
case 3:
printf("Selected 3\n");
printf("Enter search length: ");
int wordLength;
scanf(" %d", &wordLength);
int wordLengthwordCount = searchByLength(textInput, textLines, wordLength);
printf("Number of words with length %d = %d", wordLength, wordLengthwordCount);
break;
default:
printf("Invalid Input.\n");
}
}
printf("You Have Quit!\n");
}
return 0;
}

Resources