#include <stdio.h>
#include <string.h>
typedef struct {
char name[11];
int score;
} report;
int main() {
int n = 3;
report student[n];
for (int i = 0; i < 3; i++) {
scanf("%[^\#]#%d", student[i].name, &student[i].score);
}
// Input name that we search.
char search[11];
scanf("%s", search);
// bubble sort
for (int a = 0; a < n - 1; a++) {
for (int b = 0; b < n - 1 - a; b++) {
if (student[b].score < student[b+1].score) {
report temp;
strcpy(temp.name, student[b].name);
temp.score = student[b].score;
strcpy(student[b].name, student[b+1].name);
student[b].score = student[b+1].score;
strcpy(student[b+1].name, temp.name);
student[b+1].score = temp.score;
}
}
}
// binary search
int left = 0;
int right = n - 1;
int middleIndex;
int rank;
while (left <= right ) {
middleIndex = (int)(left + right) / 2;
if (strcmp(student[middleIndex].name, search) == 0) {
rank = middleIndex+1;
break;
} else if (strcmp(student[middleIndex].name, search) > 0) {
left = middleIndex + 1;
} else if (strcmp(student[middleIndex].name,search) < 0) {
right = middleIndex - 1;
}
}
// Rank of the student's name that we search.
printf("%d", rank);
return 0;
}
I want to create a program that will return a student ranking (from 3 students). The fourth line is the name that we searched. I put all the user input into a struct and sort it in descending order to represent students ranking. But the problem is, when it reach the binary search, it always return unexpected value. Could you guys help me solve the problem?
Sample Input :
Jojo#40
Ray#60
Liz#80
Jojo -> name that we searched.
""" [ {Liz, 80}, {Ray, 60}, {Jojo,40} ] """
Output : 3
At least one problem is that your names (except the first) will have a newline as the first character. That newline was left in the input stream when scanning the score.
Consequently your string compare doesn't work.
Add this
for (int a = 0; a < 3; a++) printf("|%s|\n", student[a].name);
printf("|%s|\n", search);
just after scan of search and you get the output:
|Jojo|
|
Ray|
|
Liz|
|Jojo|
As you can see there are "unexpected" newlines in front of both "Ray" and "Liz"
To solve that add a space here
scanf(" %[^\#]#%d"
^
space
As noted by #EricPostpischil in a comment, sorting by score and doing binary search by name makes no sense. The sort and the search must be based on the same.
BTW: When sorting arrays use qsort
The below code reads and stores the content of a .txt file into an array.
However instead of printing all the names in the file, it only prints the last line Matthew 789 30 times. My print function looks right but not sure where am I going wrong.
main
while (fscanf( in , "%s %s", name, num) == 2) {
array_of_students[i] = make_node(name, num);
}
printf("\nOriginal unsorted array\n");
print_array(array_of_students, 30);
Function:
Student * make_node(char * name, char * number) {
Student * new_student;
new_student = (Student * ) malloc(CLASS_SIZE * sizeof(Student));
int i = 0;
new_student[i].name = NULL;
new_student[i].number = NULL;
new_student[i].name = name;
new_student[i].number = number;
i++;
return new_student;
}
void print_array(Student * array_of_students[], int size) {
for (int i = 0; i < 30; i++) {
printf("%s %s\n", array_of_students[i] -> name, array_of_students[i] -> number);
}
}
txt file:
John 123
Walter 456
Matthew 789
You're assigning the same pointer values for name and number for each Student object you're creating, and overwriting the arrays those pointers point to each time.
You need to allocate space for the name and number members to point to space to store the strings in question and copy them over. You're also allocating space for too many Student objects. You only need one here:
Student *make_node(char * name, char * number) {
Student *new_student = malloc(sizeof(Student));
new_student->name = strdup(name);
new_student->number = strdup(number);
return new_student;
}
You also need to increment i in the scanf loop:
i = 0;
while (fscanf( in , "%s %s", name, num) == 2) {
array_of_students[i++] = make_node(name, num);
}
array_of_students[i] = make_node(name, num);
But nothing's incrementing i when you go around the loop. Should be i++?
print_array(array_of_students, 30);
Probably should pass i instead of 30.
for (int i = 0; i < 30; i++)
and you didn't use size here
I'm working on a personal project to fill an array with random numbers, split into a number of user defined segments using pthread (POSIX), search for a target in each segment, and return the number of times the target was found. I'm having bugs and issues. For more than one thread, issues like the target not being held in the struct member and a thread not being created and other things happen. I'm sure my logic is off and my code and it's output reflect this, but I'm stumped. How would you split an array into threads? What logic am I messing up?
HEADER FILE...
#ifndef COUNT_ARRAY_H
#define COUNT_ARRAY_H
// structure declarations
typedef struct
{
int threadNum;
int *array;
int first;
int last;
int target;
int numFound;
} ThreadInfo;
// function prototypes
void* ThreadFunc(void *vptr);
#endif // COUNT_ARRAY_H
MAIN FILE....
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include "count_array.h"
int main(void)
{
int numSegs;
int numSegElems;
int maxRand;
int target;
int totalElems;
int totalFound = 0;
ThreadInfo *infoPtr;
pthread_t *threadHandles;
int index = 0;
int first;
int last;
int threadNum = 0;
//get primary info from user...
printf(" Please enter the total number of elements? ");
scanf("%d", &totalElems);
printf(" Please enter the maximum random value: ");
scanf("%d", &maxRand);
printf(" Please enter the number of segments (1 to 15857): ");
scanf("%d", &numSegs);
if(numSegs > 15857)
{
puts(" Too many segments for machine!");
exit(EXIT_FAILURE);
}
numSegElems = totalElems/numSegs;
// configure the array to work with
// declare array here...
int myArray[totalElems];
//and fill array here
for(; index < totalElems; index++)
{
// % rand() and maxRand to get good range and
//not go beyond users max number
myArray[index] = (rand() % maxRand);
//test printf...ignore if still here
printf(" %d \n", myArray[index]);
}
// get the target value to look for
printf(" Please enter the target value: ");
scanf("%d",&target);
// display initial information
printf("*** Begin search: target = %d, # elements = %d, # segments = %d, "
"# segment elements = %d\n"
, target
, totalElems
, numSegs
, numSegElems);
// initialize the array first/last indexes into the integer array
if(numSegs == 1)
{
first = totalElems;
last = 0;
}
else
{
first = totalElems - numSegElems;
last = (first - numSegElems);
}
// allocate an array to store the thread handles
int size; //size of segment
if(numSegs > 1)
{
size = numSegElems;
}
else
{
size = totalElems;
}
//test printf...please ignore if still here
//printf(" size %d \n", size);
int segA[size];//not sure if I need this
// loop and create threads (# of segments)
index = 0;
for(; threadNum < numSegs; index++)
{
// allocate a thread info structure from the heap
threadHandles = calloc(totalElems, sizeof(pthread_t));
infoPtr = calloc(totalElems, sizeof(ThreadInfo));
// store the information in the allocated structure
infoPtr[index].threadNum = threadNum;
infoPtr->target = target;
infoPtr->first = first;
infoPtr->last = last;
infoPtr->array = myArray;
// create the secondary thread, passing the thread info
pthread_create(&threadHandles[index], NULL, ThreadFunc, &infoPtr[index]);
// update the first/last array indexes for the next thread
first = last;
last = first-numSegs;
++threadNum;
}
// loop and join the threads to fetch each thread's results
for(index = 0; index < numSegs; index++)
{
// join with the next thread
pthread_join(threadHandles[index], NULL);
// get the total number of matches from the thread's infoPtr
// and display a message
printf(" *** pthread_join returned: threadNum = %d, numFound = %d\n",
infoPtr[index].threadNum, infoPtr->numFound);
}
// release the infoPtr structure back to the heap
free(infoPtr);
// display the final results
// release heap memory
free(threadHandles);
return 0;
} // end of "main"
void* ThreadFunc(void *vptr)
{
//declare and set vars
ThreadInfo *ptr = vptr;
ptr->numFound = 0;
int index = ptr->first-1;
//test printf...ignore if still here
printf(" Targ %d \n", ptr->target);
//start search
for(; index >= ptr->last; --index)
{
printf(" %d \n", ptr->array[index]);
//if target found
if(ptr->target == ptr->array[index])
{
puts(" Target found! ");
//increment numFound
++ptr->numFound;
}
}
//drop out and display message
}
You've got multiple errors in your allocation of threadHandles and infoPtr. First, you don't really want to be allocating totalElems of them -- you only need numSegs. Second, and more crucially, you're reallocating them and changing the values of the pointers infoPtr and threadHandles every time through the thread invocation loop. Third, you've mixed treating infoPtr as an array of ThreadInfo structures here:
infoPtr[index].threadNum = threadNum;
with treating it as a pointer to a changing ThreadInfo structure here:
infoPtr->target = target;
infoPtr->first = first;
infoPtr->last = last;
infoPtr->array = myArray;
so every time through the loop, you're setting these parameters on the first thread only.
To fix this, edit and move the allocations before the loop and treat infoPtr consistently as an array:
threadHandles = calloc(numSegs, sizeof(pthread_t));
infoPtr = calloc(numSegs, sizeof(ThreadInfo));
for(; threadNum < numSegs; index++)
{
infoPtr[index].threadNum = threadNum;
infoPtr[index].target = target;
infoPtr[index].first = first;
infoPtr[index].last = last;
infoPtr[index].array = myArray;
and also fix up the second use of infoPtr in this printf a little further down:
printf(" *** pthread_join returned: threadNum = %d, numFound = %d\n",
infoPtr[index].threadNum, infoPtr[index].numFound);
and things will work a little better.
There are still more bugs lingering in your setting of first and last. I suggest you print out their values and make sure they are coming out the way you intend. I was able to get them to become negative (and start searching random memory) pretty easily.
Well I have only learnt C programming for 2 months. The code I got here is to solve a cashier system. I got some bar code number, item name and price. After cashier types in a numbers of bar codes and finishes with F, a receipt with item number, code and price should be shown.
These are the codes I compiled. However, I can only type one bar code and the program crashed.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
typedef struct goods
{
char goods_code[6];
char goods_descrip[20];
float price;
}goodtype;
goodtype goods[13];
strcpy(goods[0].goods_descrip, "Chicken");
strcpy(goods[0].goods_code, "00310");
goods[0].price = 35.00;
strcpy(goods[1].goods_descrip, "Pork");
strcpy(goods[1].goods_code, "00311");
goods[1].price = 20.50;
strcpy(goods[2].goods_descrip, "Beef");
strcpy(goods[2].goods_code, "00322");
goods[2].price = 45.00;
strcpy(goods[3].goods_descrip, "Fish");
strcpy(goods[3].goods_code, "00323");
goods[3].price = 40.00;
strcpy(goods[4].goods_descrip, "Walmart T Shirt");
strcpy(goods[4].goods_code, "00510");
goods[4].price = 75.00;
strcpy(goods[5].goods_descrip, "Walmart Trousers");
strcpy(goods[5].goods_code, "00511");
goods[5].price = 120.00;
strcpy(goods[6].goods_descrip, "Walmart Coat");
strcpy(goods[6].goods_code, "00512");
goods[6].price = 100.00;
strcpy(goods[7].goods_descrip, "Walmart Jumper");
strcpy(goods[7].goods_code, "00513");
goods[7].price = 85.00;
strcpy(goods[8].goods_descrip, "Mug");
strcpy(goods[8].goods_code, "00710");
goods[8].price = 15.50;
strcpy(goods[9].goods_descrip, "Fry Pan");
strcpy(goods[9].goods_code, "00711");
goods[9].price = 200.00;
strcpy(goods[10].goods_descrip, "Bowl");
strcpy(goods[10].goods_code, "00712");
goods[10].price = 25.00;
strcpy(goods[11].goods_descrip, "Dish");
strcpy(goods[11].goods_code, "00713");
goods[11].price = 25.00;
char tempCode[6];
char receiptNM[20], receiptCD[6];
char stop[2] = {"F"};
float receiptPC, ttlcost = 0;
unsigned int i;
printf("Please enter the item code. Type F to finish");
scanf("%s", &tempCode);
while ( strcmp(tempCode, stop) ){
for (i = 0; i <= 12; ++i){
if (strcmp(tempCode, goods[i].goods_code) == 0){
strcpy(receiptNM, goods[i].goods_descrip);
strcpy(receiptCD, goods[i].goods_code);
receiptPC = goods[i].price;
ttlcost += goods[i].price;
}
else{
printf("This item code does not exist! Try again!\n");
}
printf("Please enter the item code. Type F to finish");
scanf("%s", &tempCode);
}
printf("_____________________________________\n\n");
printf(" THANK YOU FOR VISITING US! \n");
printf("_____________________________________\n");
printf(" Here is your receipt: \n\n");
printf("%10s%20s%10s", "Item", "Code", "Price");
printf("%10s%20s%10.2f\n", receiptNM, receiptCD, receiptPC);
printf("\n_____________________________________\n");
printf(" TOTAL COST:%.2f \n", ttlcost);
}
I'm struggling with this for hours and cannot fix it out.
An example output should beSample receipt
When I type 00310, the program cannot recognize it. While as I type 310 it can.
Also, when the code typed does not exist, the error message should only display once. But in my programm, it does 12 times.
You have made couple of mistakes. Let me point out them:-
First one pointed by Keine Lust: https://stackoverflow.com/a/40690102/3959321, where you're accessing memory out of bounds of array by iterating to 12 (inclusive). If you've declared an array of 12 elements, the indices range from 0 to 11 and not 0 to 12
for (i = 0; i <= 12; ++i){ //wrong iterations (< 12 should be here)
if (strcmp(tempCode, goods[i].goods_code) == 0) {
strcpy(receiptNM, goods[i].goods_descrip);
strcpy(receiptCD, goods[i].goods_code);
receiptPC = goods[i].price;
ttlcost += goods[i].price;
}
else {
printf("This item code does not exist! Try again!\n");
}
printf("Please enter the item code. Type F to finish");
scanf("%s", &tempCode);
}
Your program definitely will print "This item code doesn't exist!..." 12 times, as the else part is associated with an if and nested inside a for loop.
So, it will be called each time when item is not found for 12 iterations of the loop.
The correct program is:-
---- //Rest above is same
unsigned int i;
printf("Please enter the item code. Type F to finish");
scanf("%s", tempCode);
while ( strcmp(tempCode, stop) ) {
for (i = 0; i < 12; ++i){
if (strcmp(tempCode, goods[i].goods_code) == 0){
strcpy(receiptNM, goods[i].goods_descrip);
strcpy(receiptCD, goods[i].goods_code);
receiptPC = goods[i].price;
ttlcost += goods[i].price;
break;
}
}
if (i==12) //The loop iteration is complete, and i becomes 12 only when the for above hasn't been breaked (same as item found)
printf("This item code does not exist! Try again!\n");
printf("Please enter the item code. Type F to finish");
memset(tempCode,'\0',sizeof(tempCode));
scanf("%s", tempCode);
}
You are also making a mistake in the final reciept part:-
printf("%10s%20s%10s", "Item", "Code", "Price");
printf("%10s%20s%10.2f\n", receiptNM, receiptCD, receiptPC); //receiptNM, receiptCD and receiptPC are only single character arrays.
They will store only one string unlike your expectation. In order to store all of them you make an array of a structure (that contains item code, name of item, and price). Follow GumBoy's answer:-
https://stackoverflow.com/a/40690211/3959321
Here
for (i = 0; i <= 12; ++i){
if (strcmp(tempCode, goods[i].goods_code) == 0){
You are accessing to uninitialized values in the last iteration (undefined behaviour), because you just filled from goods[0] to goods[11]:
strcpy(goods[11].goods_descrip, "Dish");
strcpy(goods[11].goods_code, "00713");
goods[11].price = 25.00;
Looking at your output image. You are going to need a for loop to print out the values. In your current program the value of receiptCD, reciptNM and recieptPC are being replaced every time the condition in your if statement is met. I think you need to add another typedef struct for your receipts.
I fixed a few problems, but you are almost there. The last thing is of the justification of the text.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
typedef struct goods
{
char goods_code[6];
char goods_descrip[20];
float price;
}goodtype;
goodtype goods[13];
strcpy(goods[0].goods_descrip, "Chicken");
strcpy(goods[0].goods_code, "00310");
goods[0].price = 35.00;
strcpy(goods[1].goods_descrip, "Pork");
strcpy(goods[1].goods_code, "00311");
goods[1].price = 20.50;
strcpy(goods[2].goods_descrip, "Beef");
strcpy(goods[2].goods_code, "00322");
goods[2].price = 45.00;
strcpy(goods[3].goods_descrip, "Fish");
strcpy(goods[3].goods_code, "00323");
goods[3].price = 40.00;
strcpy(goods[4].goods_descrip, "Walmart T Shirt");
strcpy(goods[4].goods_code, "00510");
goods[4].price = 75.00;
strcpy(goods[5].goods_descrip, "Walmart Trousers");
strcpy(goods[5].goods_code, "00511");
goods[5].price = 120.00;
strcpy(goods[6].goods_descrip, "Walmart Coat");
strcpy(goods[6].goods_code, "00512");
goods[6].price = 100.00;
strcpy(goods[7].goods_descrip, "Walmart Jumper");
strcpy(goods[7].goods_code, "00513");
goods[7].price = 85.00;
strcpy(goods[8].goods_descrip, "Mug");
strcpy(goods[8].goods_code, "00710");
goods[8].price = 15.50;
strcpy(goods[9].goods_descrip, "Fry Pan");
strcpy(goods[9].goods_code, "00711");
goods[9].price = 200.00;
strcpy(goods[10].goods_descrip, "Bowl");
strcpy(goods[10].goods_code, "00712");
goods[10].price = 25.00;
strcpy(goods[11].goods_descrip, "Dish");
strcpy(goods[11].goods_code, "00713");
goods[11].price = 25.00;
char tempCode[6];
typedef struct receipt
{
char receiptNM[20], receiptCD[6];
float receiptPC;
}receipttype;
receipttype receipt[13];
char stop[2] = {"F"};
float ttlcost = 0;
unsigned int i;
unsigned int count = 0;
while ( strcmp(tempCode, stop) ){
printf("Please enter the item code. Type F to finish: ");
scanf("%s", tempCode);
for (i = 0; i <= 12; ++i){
if (strcmp(tempCode, goods[i].goods_code) == 0){
strcpy(receipt[count].receiptNM, goods[i].goods_descrip);
strcpy(receipt[count].receiptCD, goods[i].goods_code);
receipt[count].receiptPC = goods[i].price;
ttlcost += goods[i].price;
count++;
}
}
}
printf("_____________________________________\n\n");
printf(" THANK YOU FOR VISITING US! \n");
printf("_____________________________________\n");
printf(" Here is your receipt: \n\n");
printf("%10s%20s%10s", "Item", "Code", "Price\n");
for (int j= 0; j < count; ++j){
printf("%10s%20s%10.2f\n", receipt[j].receiptNM, receipt[j].receiptCD, receipt[j].receiptPC);
}
printf("\n_____________________________________\n");
printf(" TOTAL COST:%.2f \n", ttlcost);
}
Since nobody else mentioned it, here's a better way to fill in the array of structs.
typedef struct
{
char *code;
char *description;
float price;
}goodtype;
static goodtype goods[] =
{
{ "00310", "Chicken" , 35.00 },
{ "00311", "Pork" , 20.50 },
{ "00322", "Beef" , 45.00 },
{ "00323", "Fish" , 40.00 },
{ "00510", "T Shirt" , 75.00 },
{ "00511", "Trousers", 120.00 },
{ "00512", "Coat" , 100.00 },
{ "00513", "Jumper" , 85.00 },
{ "00710", "Mug" , 15.50 },
{ "00711", "Fry Pan" , 200.00 },
{ "00712", "Bowl" , 25.00 },
{ "00713", "Dish" , 25.00 }
};
static int goodscount = sizeof(goods) / sizeof(goods[0]);
int main( void )
{
for ( int i = 0; i < goodscount; i++ )
printf( "%3d %s %s\n", i, goods[i].code, goods[i].description );
printf( "Number of items: %d\n", goodscount );
}
There are several advantages to doing it this way:
It takes less typing, reducing the chance for human error
Saves a little memory, since you don't need to guess how big the code and description arrays need to be.
Avoids the possibility of buffer overrun (e.g. if you guessed wrong about the length of the strings).
Saves a little time, since you don't need to do all those strcpys.
Automatically counts the number of entries in the array, so you can't get that wrong.
I have a struct gradebook with(among other things) an array of student structs that has two string fields
#define MAX_NAME_LEN 50
#define MAX_EMAIL_LEN 80
#define MAX_NUMBER_OF_STUDENTS 200
#define MAX_NUMBER_OF_ASSIGNMENTS 100
typedef struct students {
char *name;
char *email;
} Students;
typedef struct gradebook {
int number_of_students;
Students students[MAX_NUMBER_OF_STUDENTS];
int number_of_assignments;
char assignments[MAX_NUMBER_OF_ASSIGNMENTS][(MAX_NAME_LEN + 1)];
int scores[MAX_NUMBER_OF_STUDENTS][MAX_NUMBER_OF_ASSIGNMENTS];
} Gradebook;
I have an initialization function
int init_gradebook(Gradebook *book) {
int row, col, ndx, count;
book->number_of_students = 0;
count += book->number_of_students;
for(ndx = 0; ndx < MAX_NUMBER_OF_STUDENTS; ndx++) {
book->students[ndx].name = 0;
book->students[ndx].email = 0;
}
book->number_of_assignments = 0;
count += book->number_of_assignments;
for(row = 0; row < MAX_NUMBER_OF_ASSIGNMENTS; row++) {
for(col = 0; col < (MAX_NAME_LEN + 1); col++) {
book->assignments[row][col] = 0;
count += book->assignments[row][col];
}
}
for(row = 0; row < MAX_NUMBER_OF_STUDENTS; row++) {
for(col = 0; col < MAX_NUMBER_OF_ASSIGNMENTS; col++) {
book->scores[row][col] = 0;
count += book->scores[row][col];
}
}
if (count == 0) {
return 1;
} else {
return 0;
}
}
and I need to then insert, into those two string fields, the passed in strings, with my add_student function.
int add_student(Gradebook *book, char *nom, char *mail) {
int ndx, count;
if (book->number_of_students == 0) {
book->students[(book->number_of_students)].name = malloc(sizeof(51));
book->students[(book->number_of_students)].email = malloc(sizeof(81));
strcpy(book->students[(book->number_of_students)].name, nom);
strcpy(book->students[(book->number_of_students)].email, mail);
book->number_of_students++;
} else {
for (ndx = 0; ndx < book->number_of_students; ndx++) {
book->students[(book->number_of_students)].name = malloc(sizeof(51));
book->students[(book->number_of_students)].email = malloc(sizeof(81));
strcpy(book->students[(book->number_of_students)].name, nom);
strcpy(book->students[(book->number_of_students)].email, mail);
book->number_of_students++;
}
}
return 1;
}
My code compiles, but when I run it with the main function, I get a seg fault. The add_student function is what I am ultimately trying to do (copy the given string into book->student[ndx].name) If you need to see the main file or the gradebook.h file, let me know.
Edit: Thanks to all of you, this issue has been solved. The main problem, as abginfo pointed out, was my If Else + the For loop inside of it. But now I have other problems further along in my program. Haha, Thank You.
From what portion of your code I can see, I'm going to make the assumption that the init_gradebook function takes a non allocated reference to gradebook and attempts to initialize it.
In this case the gradebook reference you have has no memory allocated to it just yet. Try using the malloc() function to assign the required memory to your gradebook reference before attempting to initialize the rest of its variables.
gb = (Gradebook*)malloc(sizeof(*Gradebook));
I've changed the variable name to avoid any confusion.
To supplement varevarao's answer, you should allocate everything explicitly as a matter of habit instead of relying on segfaults to tell you something's not allocated. (Not that you necessarily do!) Messing with unallocated memory is undefined behavior, so in some cases this code does not trigger an error -
int main (void) {
Gradebook mybook;
init_gradebook(&mybook);
printf("there are %i students\n", mybook.number_of_students);
add_student(&mybook, "blerf", "blerf#gmail.com");
printf("now there are %i students\n", mybook.number_of_students);
printf("%s has an email address of %s\n", mybook.students[0].name, mybook.students[0].email);
return 0;
}
returned (on my machine)
there are 0 students
now there are 1 students
blerf has an email address of blerf#gmail.com