I am attempting to create a program that will allow a user to search for a name in a file. The program does this successfully, but then it occurred to me that not everyone will type in the name as it is capitalized in the file. That is, someone may search for "sarah," but as the name is listed as "Sarah" in the file the name will not be found. To get around this I have attempted to convert both strings into upper case at the time of comparison. I am very, very new to teaching myself C, so I am not certain if I am even heading in the right direction. At this point I cannot even get the program to compile as I am getting two errors that say "array initializer must be an initializer list or string literal." I'm assuming that to mean that my syntax is not only invalid but completely in the wrong direction. What would be the best way to approach my goal?
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main(void)
{
FILE *inFile;
inFile = fopen("workroster.txt", "r");
char rank[4], gname[20], bname[20], name[20];
printf("Enter a name: __");
scanf("%s", name);
int found = 0;
while(fscanf(inFile, "%s %s %s", rank, bname, gname)== 3)
{ char uppername[40] = toupper(name[15]);
char upperbname[40] = toupper(bname[15]);
if(strcmp(uppberbname,uppername) == 0)
{
printf("%s is number %s on the roster\n", name, rank);
found = 1;
}
}
if ( !found )
printf("%s is not on the roster\n", name);
return 0;
}
This two lines are wrong:
char uppername[40] = toupper(name[15]);
char upperbname[40] = toupper(bname[15]);
int toupper(int c); takes an int and returns an int
Because in C string is just an array of chars with a null terminator, so what you can do is to convert each character of the string to uppercase:
for (size_t I = 0; I < strlen(name); I++) {
uppername[I] = toupper(name[I]);
}
uppername[I] = '\0';
Regarding compare, you can use strcasecmp as suggested, which is Posix.
If you want to just use function in the C stdlib, convert the string as above, and then use strcmp.
toupper() works on a single character, not on a string.
No need to convert the input strings. Simple call a string case-insensitive compare.
As C does not have a standard one, it is easy enough to create your own.
int mystricmp(const char *s1, const char *s2) {
// toupper works with unsigned char values.
// It has trouble (UB) with char, when char is signed.
const unsigned char *p1 = (const unsigned char *) s1;
const unsigned char *p2 = (const unsigned char *) s2;
while (toupper(*p1) == toupper(*p2) && *p1) {
p1++;
p2++;
}
int ch1 = toupper(*p1);
int ch2 = toupper(*p1);
return (ch1 > ch2) - (ch1 < ch2);
}
use the following function, which is included in strings.h
int strcasecmp(const char *s1, const char *s2);
in your case change if statement
if(strcmp(uppberbname,uppername) == 0)
to
if(strcasecmp(bname,name) == 0)
and delete
char uppername[40] = toupper(name[15]);
char upperbname[40] = toupper(bname[15]);
Because the function toupper is for converting a character from small to capital, you cannot use it for a string case conversion. But you can string using the same function in this way:
while(name[i])
{
uppername[i]=toupper(name[i]);
i++;
}
while(bname[j])
{
upperbname[j]=toupper(bname[j]);
j++;
}
These statements do our string case conversion. The whole Program:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main(void) {
FILE *inFile;
inFile = fopen("workroster.txt", "r");
char rank[4], gname[20], bname[20], name[20], uppername[40], upperbname[40];
printf("Enter a name: __");
scanf("%s", name);
int found = 0, i = 0, j = 0;
while (fscanf(inFile, "%s %s %s", rank, bname, gname) == 3) {
while (name[i]) {
uppername[i] = toupper(name[i]);
i++;
}
while (bname[j]) {
upperbname[j] = toupper(bname[j]);
j++;
}
//char uppername[40] = toupper(name[15]);
//char upperbname[40] = toupper(bname[15]);
if (strcmp(uppername, upperbname) == 0) {
printf("%s is number %s on the roster\n", name, rank);
found = 1;
}
}
if (!found) printf("%s is not on the roster\n", name);
return 0;
}
Related
I have a task to do. I have to work with strings. I will show you the input and output, because I think that will be clear what the task is.
Input: "aaa bbuvvvvo"
Output: "a$3 b$2uv$4o"
If there is the same symbols, I have to leave that symbol and then put dollar sign '$' and an integer of how many same signs was there. I am stuck on the spot, where I have to change string without losing any information.
I will leave my code here, it might help.
#include <stdio.h>
#include <string.h>
#define CAPACITY 255
#define MAX_NUMBER 10
void Output(char readFile[], char outputFile[], char string[]);
void changeString(char string[], char newString[]);
int main() {
char readFile[CAPACITY];
char outputFile[CAPACITY];
char string[CAPACITY];
// Input file's name
printf("Iveskite teksto failo varda: ");
scanf("%s", &readFile);
// Output file's name
printf("Iveskite teksto faila i kuri bus isvedamas atsakymas: ");
scanf("%s", &outputFile);
Output(readFile, outputFile, string);
return 0;
}
// Scanning file
void Output(char readFile[], char outputFile[], char string[])
{
char newString[CAPACITY];
FILE *input, *output;
input = fopen(readFile, "r");
while(fscanf(input, "%s", string) != EOF)
{
changeString(string, newString);
printf("%s\n", newString);
}
}
// Changing string to wanted string
void changeString(char string[], char newString[])
{
char number[MAX_NUMBER];
int symbols = 0;
int j;
for(int i = 0; string[i] != '\0'; ++i)
{
int temp = i;
newString[i] = string[i];
if(newString[i] == string[i + 1])
{
j = i;
while(string[j] == string[i])
{
++symbols;
++j;
}
// Changing int to char
sprintf(number, "%d", symbols);
newString[i + 1] = '$';
i += 2;
newString[i] = number[0];
symbols = 0;
}
}
}
I have tried to do that with function called changeString, but I get the wrong output all the time. Also the input I am getting is from .txt file.
EDIT: When I compiling this program right now, I get a$3 b$2v$4vo that output.
For starters this declaration in main
char string[CAPACITY];
does not make sense.
You should declare variables in scopes where they are used.
The variable string is used in the function Output where it is should be declared.
The function changeString should be declared like
void changeString( const char string[], char newString[]);
because the source string is not changed within the function.
Your function has several bugs.
For example it does not build a string in the array newString because it does not append the stored sequence in the array with the terminating zero character '\0'.
Secondly this increasing of the variable i
i += 2;
in general is invalid. You need to add to the variable i the number of repeated characters in the source string.
Or the number of repeated characters change greater than or equal to 10. In this case this statement
newString[i] = number[0];
will not produce correct result.
The function can be defined the following way as shown in the demonstration program below.
#include <stdio.h>
#define CAPACITY 255
void changeString( const char string[], char newString[] )
{
while ( *string )
{
*newString++ = *string;
size_t n = 1;
while (*++string == *( newString - 1 ) ) ++n;
if (n != 1)
{
*newString++ = '$';
int count = sprintf( newString, "%zu", n );
newString += count;
}
}
*newString = '\0';
}
int main( void )
{
char string[CAPACITY] = "aaa bbuvvvvo";
char newString[CAPACITY];
changeString( string, newString );
puts( newString );
}
The program output is
a$3 b$2uv$4o
I have found some information about strcat and experimented with it but it doesn't work the way i expected for example :
char a = 'a', b = 'b';
strcat(a,b);
printf("%c", a);
this will produce an error "initialization of 'char' from 'char *' makes integer from pointer without a cast". Is there a way to unite chars until the wanted word is complete and store it in 1 variable? Or am i going completely wrong about this. The purpose of the code is to read an xml file and build a tree with the tags.
Any help is or advice is very much appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
int count = 0;
char c, word;
FILE *file = fopen("example.xml", "r");
if (file == NULL) {
return 0;
}
do {
c = fgetc(file);
if (c == '<') {
count = 1;
}
if (c == '>') {
count = 0;
printf(">");
}
if (count == 1) {
printf("%c", c);
}
if (feof(file)){
break ;
}
} while(1);
fclose(file);
return(0);
}
I'm not sure exactly what you're trying to accomplish, but you could try something like the following, which will print every <tag>, i.e., every string in the file between <...>'s , and will also accumulate them in an array of strings called tags[]. And note that you'd might want to add checks that avoid going over the 99 chars/tag and 999 tags total. But if this isn't anything like what you're actually trying to do, maybe clarify the question.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
int ntags=0, ichar=0,nchars=0;
char c='\000', tags[999][99];
FILE *file = fopen("example.xml","r");
if (file==NULL) return(0);
while((ichar=fgetc(file))!=EOF) {
c = (char)ichar;
if (nchars==0 && c!='<') continue;
tags[ntags][nchars++] = c;
if (c=='>') {
tags[ntags][nchars] = '\000';
printf("tag#%d = %s\n",ntags+1,tags[ntags]);
nchars=0; ntags++; }
}
/* do you now want to do anything with your tags[] ??? */
fclose(file);
return(0);
}
You are trying to use a function, those parameters are char *
char *strcat(char *dest, const char *src)
but you gave strcat a char but it wants a char*
int main()
{
char str1[20] = "this";
char str2[] = "is";
strcat(str1, str2);
printf("%s", str1);
return 0;
}
this is the way i thinkt you want it
char* str =
"\
a-a-a-a\
differing the text, because that was the lecture thing\
the text has been changed\
I know!\
the text has been changed\
";
i deeply thinking about this for hours but can`t figure it out..
with using only stdio.h
string.h is not allowed, but using only basic things..
how can I get string length? someone please help me.
the goal is to find frequency of input pattern in a given string
ex) ha => 2, di => 1..
help me.
As for length of string, the implementation of strlen isn't very complicated.
All you should do is to loop over the string until you find a \0 (end of string) and count the number of times you looped.
unsigned int mystrlen(const char* str)
{
unsigned int length = 0;
while (*str != 0)
{
str++;
length++;
}
return length;
}
This could be shortened into
unsigned int len = 0;
for (; str[len]; len++);
A string in pure C is just a pointer to a memory.
IF the last element is 0, then you can use strlen or whatever checks for that.
But if that is not the case you need to memorize the length in a variable.
So if it is 0-terminated just loop to the first element that is 0 (not '0') and thats the end. If you counted the elements you have the string-length.
This works for some test input string, but i higly recommend to check it with more cases.
Suppose we have implemented strstr().
strstr()
Is a C library function from string.h Library
char *strstr(const char *haystack, const char *needle)
This function finds the first occurrence of the substring needle in the source string haystack.
The terminating \0 characters are not compared.
source: TutorialsPoint
(with some edition)
Code
#include <stdio.h>
#include <string.h>
unsigned int Neostrlen(const char* str)
{
unsigned int length = 0;
while (*str != 0)
{
str++;
length++;
}
return length;
}
int BluePIXYstrlen(char* str)
{
int len = 0;
sscanf(str, "%*[^0]%n", &len);
return len;
}
int Jeanfransvastrlen(char* str)
{
int i;
for (i=0;str[i];i++);
return i;
}
int main(int argc, char **argv){
//is it true, no need to malloc????
char* str =
"\
P-P-A-P\
I have a pen, I have a apple\
Uh! Apple-Pen!\
I have a pen, I have pineapple\
Uh! Pineapple-Pen!\
Apple-Pen, Pineapple-Pen\
Uh! Pen-Pineapple-Apple-Pen\
Pen-Pineapple-Apple-Pen\
";
printf("len: %d\n", Jeanfransvastrlen(str));
printf("len: %d\n", Neostrlen(str));
printf("len: %d\n", BluePIXYstrlen(str));
printf("sss:%s\n\n\n", str);
char * search = "have";//search for this substring
int lenSr= Neostrlen(search);
printf("lenSr: %d\n", lenSr);
char * ret;
ret = strstr(str, search);
int count = 0;
while (ret){
//printf("The substring is: %s\n\n\n\n", ret);
count++;
for (int i=0;i<lenSr;i++){
printf("%c", ret[i]);
}
printf("\nEnd sub\n");
for (int i=0;i<lenSr;i++){
ret++;
}
ret = strstr(ret, search);
}
printf("count: %d\n", count);
return 0;
}
Edited
For only using stdio.h you can substitute all strstr() with this version of mystrstr() adopted from leetcode
mystrstr()
char* mystrstr(char *str, const char *target) {
if (!*target) {
return str;
}
char *p1 = (char*)str;
while (*p1) {
char *p1Begin = p1, *p2 = (char*)target;
while (*p1 && *p2 && *p1 == *p2) {
p1++;
p2++;
}
if (!*p2){
return p1Begin;
}
p1 = p1Begin + 1;
}
return NULL;
}
Hint
I removed const from first first argument of mystrstr() because of I want to change it later, and this is the only changed i have made on original code.
This version is sensitive to Uppercase and lowercase letters in string,
for example Apple is differ from apple.
As chux said in comments my code return substrings of "ababa" from source
"aba" only {aba} not more. and this is because i change string pointer inside while in last for.
Suggestion
Try to implement your version of strstr(), and strlen()
I have a struct defined as;
struct player {
int no, age;
char name[20];
} players[10];
Array is filled from file. What I try to do is, take input from user, add input to char array, send it to search(char lookup[]) function and strstr name field in a loop.
EDİT: Sorry I corrected the order. I'm trying to strstr in a loop.
char *p = strstr(players[x].name, inputFromUser);
but p is always null. How can I do this?
Thanks in advance.
EDIT - Code Added...
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
struct player {
int no, age;
char name[20];
} players[20];
void fillstruct(char *);
void search(char []);
int main(int argc, char *argv[])
{
int arg;
int c;
int d;
int i=0;
char a[100];
char *filename = NULL;
while((arg=getopt(argc, argv, "f:"))!=-1)
{
switch(arg)
{
case 'f':
filename = optarg;
fillstruct(filename);
break;
default:
break;
}
}
while((c=fgetc(stdin))!=EOF)
{
if(c!=10)
{
a[i]=c;
i++;
}
else
{
a[i]='\0';
search(a);
i=0;
}
}
return 0;
}
void search(char a[])
{
int i=0;
int col;
int found=0;
char *p =NULL;
while((i<20)&&(found==0))
{
p = strstr(a, players[i].name);
if(p)
{
col = p-a;
printf("\nPlayer '%s' found in '%s'.. Found index: %d", a, players[i].name, col);
found=1;
}
else
{
printf("\np=%s a=%s player[%d].name=%s", p, a, i, players[i].name);
}
i++;
}
}
void fillstruct(char *name)
{
FILE *fp;
char line[100];
int i=0;
fp = fopen(name, "r");
if(fp==NULL)
{
exit(1);
}
while(fgets(line, 100, fp)!=NULL)
{
players[i].no=i;
strcpy(players[i].name, line);
fprintf(stdout, "\nplayer=%s", players[i].name);
players[i].age=20;
i++;
}
fclose(fp);
}
Added as answer as suggested by mic_e
Assuming you're trying to search for a player name using the input from a user, you have the arguments of strstr in the reverse order. Also note that strstr is case sensitive.
char *p = strstr(players[x].name, inputFromUser);
fgets stores the \n and then stops taking input.
So suppose a player name is "user", players[i].name will be equal to "user\n" while a is "user".
So return of strstr is always NULL.
Try this instead:
p = strstr(players[i].name,a);
OR, remove the \n after taking input from file by fgets:
while(fgets(line, 100, fp)!=NULL)
{
players[i].no=i;
strcpy(players[i].name, line);
players[i].name[strlen(players[i].name)-1]='\0'; //add this line
fprintf(stdout, "\nplayer=%s", players[i].name);
players[i].age=20;
i++;
}
Like this:
char *p = strstr(players[x].name, inputFromUser);
It should work, It's fail if your input is wrong let me expalain in simple
int main()
{
char *ret;
char mystr[]="stack";
char str[]="This is stack over flow string";
ret = strstr(str, mystr);
printf("The substring is: %s\n", ret);
return(0);
}
Output is
The substring is: stack over flow string
That means
This function returns a pointer to the first occurrence in str of any of the entire sequence of characters specified in mystr, or a null pointer if the sequence is not present in str.
It case sensitive function means if try to search like
char mystr[]="Stack";//Note here first char is capital
And you got output like
The substring is: (null)
You can check your input and target string at your side by just printing content of it and verify it's correct or not.
printf("str1:%s str2:%s\n",players[x].name,inputFromUser)
char *p = strstr(players[x].name, inputFromUser);
I hope this clear your doubts.
That Should Work.
I think You have the problem with file reading Which fills the data array.
Please make sure that data you filled into structure is Ok.
And strstr returns address of the first Occurrence of the string1 in string2
where,
strstr(string2, string1);
Here is a program to accept a:
Sentence from a user.
Word from a user.
How do I find the position of the word entered in the sentence?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char sntnc[50], word[50], *ptr[50];
int pos;
puts("\nEnter a sentence");
gets(sntnc);
fflush(stdin);
puts("\nEnter a word");
gets(word);
fflush(stdin);
ptr=strstr(sntnc,word);
//how do I find out at what position the word occurs in the sentence?
//Following is the required output
printf("The word starts at position #%d", pos);
return 0;
}
The ptr pointer will point to the beginning of word, so you can just subtract the location of the sentence pointer, sntnc, from it:
pos = ptr - sntnc;
Just for reference:
char saux[] = "this is a string, try to search_this here";
int dlenstr = strlen(saux);
if (dlenstr > 0)
{
char *pfound = strstr(saux, "search_this"); //pointer to the first character found 's' in the string saux
if (pfound != NULL)
{
int dposfound = int (pfound - saux); //saux is already pointing to the first string character 't'.
}
}
The return of strstr() is a pointer to the first occurence of your "word", so
pos=ptr-sntc;
This only works because sntc and ptr are pointers to the same string. To clarify when I say occurence it is the position of the first matching char when the matching string is found within your target string.
You can use this simple strpos modification
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int strpos(char *haystack, char *needle, int offset);
int main()
{
char *p = "Hello there all y'al, hope that you are all well";
int pos = strpos(p, "all", 0);
printf("First all at : %d\n", pos);
pos = strpos(p, "all", 10);
printf("Second all at : %d\n", pos);
}
int strpos(char *hay, char *needle, int offset)
{
char haystack[strlen(hay)];
strncpy(haystack, hay+offset, strlen(hay)-offset);
char *p = strstr(haystack, needle);
if (p)
return p - haystack+offset;
return -1;
}
For some reasons I was having trouble with strstr(), and I also wanted index.
I made this function to find the position of substring inside a bigger string (if exists) otherwise return -1.
int isSubstring(char * haystack, char * needle) {
int i = 0;
int d = 0;
if (strlen(haystack) >= strlen(needle)) {
for (i = strlen(haystack) - strlen(needle); i >= 0; i--) {
int found = 1; //assume we found (wanted to use boolean)
for (d = 0; d < strlen(needle); d++) {
if (haystack[i + d] != needle[d]) {
found = 0;
break;
}
}
if (found == 1) {
return i;
}
}
return -1;
} else {
//fprintf(stdout, "haystack smaller\n");
}
}
My comment to the ORIGINAL post in this thread:
This declaration is INCORRECT:
char sntnc[50], word[50], *ptr[50];
C code would not even compile : it will fail on this line:
ptr = strstr(sntnc,word);
So the line shall be changed to :
char sntnc[50], word[50], *ptr;
And you do NOT need memeory allocated to 'ptr string'. You just need a pointer to char.