I'm having some trouble with the output of this program. I need to print the verbs on one line, and I need to print a separate statement in the case that there are no verbs. For ex.
"talk and walk" should print "The verbs are: talk walk"
while "hello there" should print "There are no verbs"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int binary_search(char *list_of_words[], int size, char *target){
int bottom= 0;
int mid;
int top = size - 1;
int found = 0;
while(bottom <= top && !found){
mid = (bottom + top)/2;
if (strcmp(list_of_words[mid], target) == 0){
//printf("%s found at location %d.\n", target, mid+1);
found = 1;
} else if (strcmp(list_of_words[mid], target) > 0){
top = mid - 1;
} else if (strcmp(list_of_words[mid], target) < 0){
bottom = mid + 1;
}
}
if (found == 1)
return mid;
else
return -1;
}
int main(int argc, char* argv[]){
char *input = strtok(argv[1], " \"\n");
char *verbs[5] = { "do", "make", "take", "talk", "walk" };
int position;
int check = 0;
while (input != NULL) {
//printf("%s\n", input);
position = binary_search(verbs, 5, input);
if (position != -1)
printf("The verbs are: %s\n", verbs[position]);
check = 1;
input = strtok(NULL, " ");
}
if (check == 0){
printf("There are no verbs\n");
}
return 0;
}
Any ideas?
It seems to be working fine, but you need to add parenthesis around
if (position != -1)
printf("The verbs are: %s\n", verbs[position]);
check = 1;
like in
if (position != -1) {
printf("The verbs are: %s\n", verbs[position]);
check = 1;
}
otherwise check is always set 1 in the loop.
And if you do not want to repeat "The verbs are:" , add a check for that
if (position != -1) {
if (first) {
printf("The verbs are:");
first = 0;
check = 1;
}
printf(" %s", verbs[position]);
}
int main(int argc, char* argv[]){
char *input = strtok(argv[1], " \"\n");
char *verbs[5] = { "do", "make", "take", "talk", "walk" };
char match[5] = {0};
int position;
int check = 0;
while (input != NULL) {
//printf("%s\n", input);
position = binary_search(verbs, 5, input);
if (position != -1){
//printf("The verbs are: %s\n", verbs[position]);
match[position]=1;//match[position] = check = 1;
check = 1;
}
input = strtok(NULL, " ");
}
if (check == 0){
printf("There are no verbs\n");
} else {
int i;
printf("The verbs are: ");
for(i=0;i<5;++i)
if(match[i])
printf("%s ", verbs[i]);
printf("\n");
}
return 0;
}
If you're more interested in just having the search done, rather than implementing it yourself (i.e., assuming "implement a search" is not your actual task), you should use the standard library's little-known hero, bsearch().
Note that this requires the input data (the array you're searching in) to be sorted, but yours seems to be since you're already working on a binary search.
Related
So I have this code which I was working on. The goal is to search for a string in a file and when that string is found it would return the corresponding values in that section of the file. So this is the file in question that is being searched:
So if it finds "AJ" then it would return all the values right up to "22550" and if it finds "TS" then it prints everything after "TS" and after "60500." This is my code in question:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char *name;
char *code;
int grpsize;
char route;
char *package;
//float fee;
float tcost;
float fcost;
} bookingrecord;
int main() {
FILE *fptr;
bookingrecord bookingrec;
char book_code[5];
printf("\n Please enter the code that corressponds to your record: ");
scanf("%s", book_code);
fptr = fopen("bookingdata", "r");
if (fptr == NULL) {
printf ("\nSorry we didn't find your file.");
exit (1);
}
ssize_t read;
char * line = NULL;
size_t len = 0;
int count = 0;
int found = 0;
while ((read = getline(&line, &len, fptr)) != -1) {
if (count == 0) {
bookingrec.code = line;
//printf("%s %s",bookingrec.code,book_code);
if (strcmp(bookingrec.code, book_code) == 0) {
found = 1;
}
} else if (count == 1 && found == 1) {
bookingrec.grpsize = line;
} else if (count == 2 && found == 1) {
bookingrec.route = line;
} else if (count == 3 && found == 1) {
bookingrec.fcost = strtof(line, NULL);
} else if (count == 4 && found == 1) {
bookingrec.name = line;
} else if (count == 5 && found == 1) {
bookingrec.package = line;
} else if (count == 6 && found == 1) {
bookingrec.tcost = strtof(line, NULL);
}
count = count + 1;
if(strlen(line) == 0) {
count = 0;
}
}
if (found == 1) {
printf("\n We have found your file");
printf("\n %s", bookingrec.code);
printf("\n %s", bookingrec.name);
printf("\n %d", bookingrec.grpsize);
printf("\n %s", bookingrec.route);
printf("\n %c", bookingrec.package);
printf("\n %.2f", bookingrec.tcost);
printf("\n %.2f", bookingrec.fcost);
}
fclose(fptr);
return 0;
}
The problem is that it only gives me this as the result:
So it finds the file okay but nothing happens so I uncomment a printf which I added to troubleshoot a bit right above my strcmp and get this when I enter for eg. "AJ":
I try another of the two character string. "SH" in this case and get this:
So it seems as if it is accepting any of the codes but prints the first line twice? But also discards everything else. I am a bit stumped as to what is happening. Any ideas?
Update:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char *name;
char *code;
int grpsize;
char *route;
char *package;
//float fee;
float tcost;
float fcost;
} bookingrecord;
int main() {
FILE *fptr;
bookingrecord bookingrec;
char book_code[5];
printf("\n Please enter the code that corressponds to your record: ");
scanf("%s", book_code);
fptr = fopen("bookingdata", "r");
if (fptr == NULL) {
printf ("\nSorry we didn't find your file.");
exit (1);
}
ssize_t read;
char * line = NULL;
size_t len = 0;
int count = 0;
int found = 0;
while ((read = getline(&line, &len, fptr)) != -1) {
line[strcspn(line, "\r\n")] = 0; //trims getLine
//printf("line is %s, count is %d \n", line, count);//debugging
if (count == 0) {
bookingrec.code = strdup(line);
if (strcmp(bookingrec.code, book_code) == 0) {
found = 1;
}
} else if (count == 1 && found == 1) {
char *tmp;
bookingrec.grpsize = strtol(strdup(line), NULL, 10);
} else if (count == 2 && found == 1) {
bookingrec.route = strdup(line);
} else if (count == 3 && found == 1) {
bookingrec.fcost = strtof(strdup(line), NULL);
} else if (count == 4 && found == 1) {
bookingrec.name = strdup(line);
} else if (count == 5 && found == 1) {
bookingrec.package = strdup(line);
} else if (count == 6 && found == 1) {
bookingrec.tcost = strtof(strdup(line), NULL);
}
count = count + 1;
if (found == 1 && count == 7){
break;
}
if(strlen(line) == 0) {
count = 0;
}
}
if (found == 1) {
printf("\n We have found your file");
printf("\n %s", bookingrec.code);
printf("\n %s", bookingrec.name);
printf("\n %d", bookingrec.grpsize);
printf("\n %s", bookingrec.route);
printf("\n %s", bookingrec.package);
printf("\n %.2f", bookingrec.tcost);
printf("\n %.2f", bookingrec.fcost);
}
fclose(fptr);
return 0;
}
Updated screens after edits:
My objective is to input a string "sana" which will at the end print only one corresponding result. Ie: if I enter the word "sana" it would print "Word sana is in English word" and if the user enters "word" it prints "Word word is in Finnish sana". So the code is not working at all so I wanted to ask how should I continue. if-else doesn't work at all but I thought it would help me visualize where to go there.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
Read file line by line
split lines using ; as delimiter
store first/second part in some array
ask user to input and search the word in that array
*/
int main()
{
FILE *fp;
char sana[30];
char *p;
void *tmp;
int lasku = 0;
int pal = 1;
int i;
char **vars = NULL;
char **vals = NULL;
fp = fopen("dictionary.txt", "r");
printf("Word: ");
scanf("%s", sana);
while (fgets(sana, sizeof(sana), fp)) {
sana[strcspn(sana, "\n")] = 0;
if (!(p = strchr(sana, ';')))
continue;
*p++ = 0; //poistaa ;
if (!strlen(sana) || !strlen(p))
continue;
if (!(tmp = realloc(vars, (lasku + 1) * sizeof(char*))))
goto out;
vars = (char**)tmp;
if (!(tmp = realloc(vals, (lasku + 1) * sizeof(char*))))
goto out;
vals = (char**)tmp;
vars[lasku] = strdup(sana);
vals[lasku] = strdup(p);
lasku++;
if (!vars[lasku-1] || ! vals[lasku-1])
goto out;
}
pal = 0;
if (i == 0 || i == 2 || i == 4)
printf("Word %s is in English %s\n", vars[i], vals[i]);
else
if (i == 1 || i == 3 || i == 5)
printf("Word %s is in Finnish %s\n", vals[i], vars[i]);
else
printf("Word can't be found in the dictionary");
out:
fclose(fp);
if (vars)
for (i = 0; i < lasku; i++)
free(vars[i]);
if (vals)
for (i = 0; i < lasku; i++)
free(vals[i]);
free(vars);
free(vals);
return pal;
}
The code does not work because:
you overwrite the word in sana when you read the dictionary.
you never set i.
testing the value of uninitialized variable i has undefined behavior.
You should first local the dictionary in memory, then read words from the user and search them in the dictionary for matches.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
Read file line by line
split lines using ; as delimiter
store first/second part in some array
ask user to input and search the word in that array
*/
int main() {
FILE *fp;
char sana[30];
char **tmp;
int lasku = 0, i, found, error = 0;
char **vars = NULL;
char **vals = NULL;
fp = fopen("dictionary.txt", "r");
while (fgets(sana, sizeof(sana), fp)) {
sana[strcspn(sana, "\n")] = '\0';
if (!(p = strchr(sana, ';')))
continue;
*p++ = '\0';
if (!*sana || !*p)
continue;
if (!(tmp = realloc(vars, (lasku + 1) * sizeof(*vars)))) {
error = 1;
break;
}
vars = tmp;
if (!(tmp = realloc(vals, (lasku + 1) * sizeof(*vals)))) {
error = 1;
break;
}
vals = tmp;
vars[lasku] = strdup(sana);
vals[lasku] = strdup(p);
lasku++;
if (!vars[lasku-1] || !vals[lasku-1]) {
error = 1;
break;
}
}
fclose(fp);
if (!error) {
for (;;) {
printf("Word: ");
if (scanf("%29s", sana) != 1)
break;
found = 0;
for (i = 0; i < lasku; i++) {
if (!strcmp(sana, vars[i]) {
printf("Word %s is in English %s\n", vars[i], vals[i]);
found = 1;
}
if (!strcmp(sana, vals[i]) {
printf("Word %s is in Finnish %s\n", vals[i], vars[i]);
found = 1;
}
}
if (!found) {
printf("Word can't be found in the dictionary");
}
}
}
for (i = 0; i < lasku; i++) {
free(vars[i]);
free(vals[i]);
}
free(vars);
free(vals);
return error;
}
I want to insert the data in ascending order based on the partNumber.
When the function is called in main, then the node is successfully added at the first position. But on calling the function second time, there is some problem in insertion and I am unable to figure it out. When I enter the values(in second call), I get the error
Process exited after 8.277 seconds with return value 3221225477
typedef struct part {
int partNumber;
char partName[200];
int partQuantity;
struct part *nextPart;
} Part;
Part *inventory = NULL;
void insertPart();
int
main(int argc, char *argv[])
{
insertPart();
insertPart();
insertPart();
insertPart();
return 0;
}
void
insertPart()
{
Part *tempPart,
*traversePart,
*swapPart;
int counter = 0;
traversePart = inventory;
tempPart = (Part *) malloc(sizeof(Part *));
printf("Enter the Part Number\n");
scanf("%d", &(tempPart->partNumber));
getchar();
printf("Enter the Part Name\n");
fgets(tempPart->partName, 200, stdin);
printf("Enter the Part Quantity\n");
scanf("%d", &(tempPart->partQuantity));
getchar();
if (inventory == NULL) {
inventory = tempPart;
printf("Part added at the first position.\n");
}
else {
while (traversePart->nextPart->partNumber < tempPart->partNumber) {
counter++;
traversePart = traversePart->nextPart;
if (traversePart->nextPart == NULL) {
break;
}
}
if (counter == 0) {
swapPart = inventory;
inventory = tempPart;
tempPart->nextPart = swapPart;
}
else if (traversePart->nextPart == NULL) {
traversePart->nextPart = tempPart;
}
else {
swapPart = traversePart->nextPart;
traversePart->nextPart = tempPart;
tempPart->nextPart = swapPart;
}
}
printf("Element added at position : %d", counter);
}
The problem is traversePart->nextPart->partNumber traversePart->nextPart is not referring to anything or it is not holding any of the address. When you insert first value if condition is true
if (inventory == NULL) {
inventory = tempPart;
printf("Part added at the first position.\n");
}
inventory now holding the address of tempPart but while assigning values of tempPart you never assign an address to its nextvalue and it's not there because you only inserted the first value. For the second position
else{
while(traversePart->nextPart!=NULL)
{
traversePart=traversePart->nextPart;
}
if(traversePart->partNumber < tempPart->partNumber){
//here you can verify conditions
traversePart->nextPart = tempPart
}
}
You're intermixing fgets and scanf [and getchar]. Better to use just fgets and then apply strtol for numbers [or sscanf].
You're linked list code is a bit convoluted. It can be simplified.
Here's the refactored code. I've pulled some helper functions that I had lying around to do the prompting.
And, I added list printing.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
typedef struct part {
int partNumber;
char partName[200];
int partQuantity;
struct part *nextPart;
} Part;
Part *inventory = NULL;
void insertPart();
int getstr(char *buf,int buflen,const char *prompt);
long getnum_strtol(const char *prompt);
int
main(int argc, char **argv)
{
insertPart();
insertPart();
insertPart();
insertPart();
for (Part *cur = inventory; cur != NULL; cur = cur->nextPart)
printf("partNumber=%d partQuantity=%d partName='%s'\n",
cur->partNumber,cur->partQuantity,cur->partName);
return 0;
}
void
insertPart(void)
{
Part *tempPart;
Part *cur;
Part *prev = NULL;
int counter = 0;
#if 0
tempPart = (Part *) malloc(sizeof(Part *));
#else
tempPart = malloc(sizeof(*tempPart));
#endif
tempPart->partNumber = getnum_strtol("Enter the Part Number");
getstr(tempPart->partName,sizeof(tempPart->partName),"Enter the Part Name");
tempPart->partQuantity = getnum_strtol("Enter the Part Quantity");
tempPart->nextPart = NULL;
// find the tail/end of the list
for (cur = inventory; cur != NULL; cur = cur->nextPart) {
++counter;
// insert in sorted part order
if (cur->partNumber > tempPart->partNumber)
break;
prev = cur;
}
do {
tempPart->nextPart = cur;
// insert in the middle or end of list
if (prev != NULL) {
prev->nextPart = tempPart;
break;
}
// insert in new list or before first element of existing list
tempPart->nextPart = inventory;
inventory = tempPart;
} while (0);
printf("\nElement added at position : %d\n", counter);
}
// getstr -- get a string with prompt
// RETURNS: length or (<0 -> error)
int
getstr(char *buf,int buflen,const char *prompt)
{
char *cp;
int ret = 0;
// NOTE: usage of the error codes in errno.h is arbitrary
while (ret <= 0) {
// ensure buffer has enough space
if (buflen < 2) {
ret = -ENOMEM;
break;
}
// output prompt
if (prompt != NULL) {
printf("%s: ",prompt);
fflush(stdout);
}
// get a line
cp = fgets(buf,buflen,stdin);
// EOF
if (cp == NULL) {
ret = -ENODATA;
break;
}
// get buffer length
ret = strlen(buf);
// empty string
if (ret <= 0)
continue;
// point to last char
cp = &buf[ret - 1];
// ensure we got a newline -- if not, fgets had to chop the line (i.e.)
// the line is too long to fit in the buffer
if (*cp != '\n') {
ret = -ENOSPC;
break;
}
// strip the newline -- we are done
*cp = 0;
--ret;
}
return ret;
}
// getnum_strtol -- get number using strtol
long
getnum_strtol(const char *prompt)
{
int len;
int readflg = 1;
char *cp;
char buf[100];
long num = 0;
while (readflg) {
len = getstr(buf,sizeof(buf),prompt);
if (len < 0)
exit(1);
num = strtol(buf,&cp,10);
// ensure we got a least one digit
if (cp <= buf)
continue;
switch (*cp) {
case ' ':
case '\t':
case 0:
readflg = 0;
break;
default:
printf("getnum_strtol: not a valid number -- buffer '%s', invalid '%s'\n",
buf,cp);
break;
}
}
return num;
}
Here's the input file I used to test:
37
Hex Bolt
12
28
Machine Screw
6
23
Brad Nail
1000
27
Lock Nut
300
Here's the program output:
Enter the Part Number: Enter the Part Name: Enter the Part Quantity:
Element added at position : 0
Enter the Part Number: Enter the Part Name: Enter the Part Quantity:
Element added at position : 1
Enter the Part Number: Enter the Part Name: Enter the Part Quantity:
Element added at position : 1
Enter the Part Number: Enter the Part Name: Enter the Part Quantity:
Element added at position : 2
partNumber=23 partQuantity=1000 partName='Brad Nail'
partNumber=27 partQuantity=300 partName='Lock Nut'
partNumber=28 partQuantity=6 partName='Machine Screw'
partNumber=37 partQuantity=12 partName='Hex Bolt'
I was presented with this code as an example of how to make a 'mini shell' but I have no idea what it is doing-- I understand most things in the main function, but the functions above it initializing I'm really quite lost on.
Any basics on how a shell works and some of the lower level functions in C would be much appreciated.
log_t Log;
void printLog(log_t *l){
log_entry_t *tmp = l->tail;
while(tmp != NULL){
printf("%s\n", tmp->value);
tmp = tmp->prev;
}
}
int countArg(char *line){
unsigned int i, count = 0;
for(i = 0; i < strlen(line); i++){
if(line[i] == ' ')
count++;
}
return count + 1;
}
char **makeargv(char *line){
char *buff;
char **retv;
unsigned int i, count, arg_num = 0;
buff = malloc((strlen(line) + 1) * sizeof(char));
strcpy(buff, line);
arg_num = countArg(buff);
retv = malloc((arg_num + 1) * sizeof(char*));
retv[arg_num] = NULL;
retv[0] = buff;
for(i = 0, count = 1; buff[i]!='\0'; i++){
if(buff[i] == ' '){
buff[i]='\0';
retv[count] = buff + i + 1;
count++;
}
}
return retv;
}
int main()
{
log_init(&Log);
char * line;
while(1){
size_t size;
char * cwd = NULL;
char * query = NULL;
char * match = NULL;
int f_exit = 0,
f_nbi=0,
f_match=0,
f_sys = 0,
f_path=0;
// print out the requested prompt
cwd = getcwd(NULL,0);
printf("$(pid=%d)%s$ ", getpid(), cwd );
free(cwd);
line = NULL;
fflush(stdout);
getline(&line, &size, stdin);
line[strlen(line)-1] = '\0';
while(1){
if(strcmp(line, "exit") == 0){
if(f_match) printf("%s matches %s\n", query, line);
f_exit = 1;
printf("Command executed by pid=%d\n",getpid());
log_destroy(&Log);
break;
}
else if(strncmp(line, "cd ", 3) == 0){
if(f_match) printf("%s matches %s\n", query, line);
printf("Command executed by pid=%d\n",getpid());
log_push(&Log, line);
if(chdir(line + 3) != 0){
printf("%s: No such file or directory\n",(line + 3));
}
break;
}
else if(strcmp(line, "!#") == 0){
if(f_match) printf("%s matches %s\n", query, line);
printf("Command executed by pid=%d\n",getpid());
printLog(&Log);
break;
}
else if(strstr(line,"!")==line){
if(f_match) printf("%s matches %s\n", query, line);
query = line+1;
match = log_search(&Log, query);
if(match==NULL){
printf("Command executed by pid=%d\n",getpid());
printf("No Match\n");
break;
}
else{
f_match = 1;
printf("Command executed by pid=%d\n",getpid());
line = malloc((strlen(match)+1)*sizeof(char));
strcpy(line, match);
continue;
}
}
else{
f_nbi = 1;
log_push(&Log,line);
if(strstr(line,"/"))
f_path = 1;
break;
}
}
if(f_exit)
break;
if(f_nbi){
pid_t pid = fork();
if(pid == 0){ //child
if(f_match){
printf("%s matches %s\n", query, line);
free(query-1);
}
printf("Command executed by pid=%d\n",getpid());
char **argv = makeargv(line);
f_sys = 0;
if(f_path)
f_sys = execv(argv[0],&argv[0]);
else
f_sys = execvp(argv[0],&argv[0]);
if(f_sys == -1)
printf("%s: not found\n",line);
free(argv[0]);
free(argv);
log_destroy(&Log);
exit(0);
}
else { //parent
waitpid(pid, NULL, WUNTRACED);
if(f_match)
free(query-1);
}
}
free(line);
line = NULL;
}
if(line != NULL){
free(line);
line = NULL;
}
return 0;
}
The printLog() function is simply printing all the data from a linked list of records in a structure type given the name log_t by a typedef. It starts at the tail of the list and works backwards. It is not clear whether the list is single-linked or double-linked, but the prev usually only appears in a double-linked list.
The countArgs() function is a crude way of determining how many arguments are present on a command line. It is crude because it does not take into account quotes or multiple adjacent spaces. However, those merely mean it overestimates the number of arguments, which is not serious. It doesn't recognize tabs as separators, which is unusual for a shell.
The makeargv() function splits a command line into a series of space separated words and returns the list of words to the calling function. It effectively parses the command line, making sure there's a null pointer at the end of the command line. Again, it is simplistic, but sufficient. It is also inconsistently named compared with the other two functions.
Working on a binary search. The code below should explain what I'm trying to do. The user inputs a word and then a binary search is implemented to search a wordlist. Problem is the binary search. It's running but it's not finding the word in the wordlist even though I know its there. I know the code could be better but it should work. Anyone shed any light?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char dictionary[400000][45];
int main(void)
{
FILE infile;
int i=0;
int num;
int index;
char buffer[45];
char userword[45];
fp1 = fopen("C:/Users/Aaron/ProgrammingAssignment/dictionary.txt","rb");
if (fp1 == NULL)
{
printf("The dictionary file did not open\n");
exit(0);
}
else
{
printf("Dictionary file is open\n");
}
while(fgets(buffer,45, fp1)!=NULL)
{
strcpy(wordlist[i],buffer);
//printf("Line %d: %s",i,wordlist[i]);
i++;
}
printf("Your wordlist is now in the dictionary array");
do
{
//fscanf(fp2,"%s", userword);
printf("Enter a word to be spell checked: ");
fgets(userword, 43, stdin);
//and do a binary search
index = BinarySearch(userword,0,i);
if(index > -1)
printf("%s was found in the wordlist", userword);
else
printf("%s was not found in the dictionary", wordcheck);
}
while(wordlist != NULL);
if(index>-1) //The word was found
{
printf("That is correctly spelled\n");
}
else
{
printf("That word is spelt wrong\n");
}
return 0;
}
int BinarySearch(const char userword[],int left,int right)
{ int high = 400000;
int low = 0;
int target;
int count = 0;
while (high >= low)
{ target = low + ((high - low) / 2);
// show tries for demonstration only
printf("%d, ",target);
if (strcmp(userword, wordlist[target]) < 0)
high = target -1;
else if (strcmp(userword, wordlist[target]) > 0)
low = target + 1;
else
return target;
}
return -1;
}
Your binary search function is ignoring the values left and right that are passed in.
It shouldn't.
It should probably start:
int BinarySearch(const char userword[], int left, int right)
{
int high = right;
int low = left;
You should close the dictionary after you finish reading it.
You need to consider whether right is the index of the last valid element or 'one after the index of the last element'. This might mean you need to pass i - 1 in the call to the function.
You should consider calling strcmp() once and capturing its return value; it is relatively expensive:
int rc = strcmp(userword, wordlist[target]);
if (rc == 0)
return target;
else if (rc < 0)
high = target - 1;
else
low = target - 1;