strstr == NULL doesn't work, - c

#include <stdio.h>
#include <string.h>
#define N 5
char username[N+3][20]={"ana","sofia","maria","isabel","joao","hugo","francisco","pedro"};
char str[20];
read_username()
{
printf("Insert your username: ");
gets(str);
}
void searchusername(int n)
{
int i;
for(i=0;i<=n;i++)
{
if(strstr(username[i], str) != NULL)
printf("username exists")
}
}
int main()
{
read_username();
searchusername(8);
}
I have the code to check if username exists, but i can´t seem to turn it around so i only get the printf when username doesn't exist, any other way without using NULL is also okay, ty.

One issue is that you are not avoiding a buffer overflow with gets(). I have to assume for this example that you are typing in short usernames that do not exceed 19 characters. Anything longer is going to cause problems if you don't account for it.
More importantly, you are not comparing the usernames correctly. You should not be using strstr() for that purpose. It searches for a substring inside of another string, it does not compare strings. For example, if you typed in ia, strstr() would match with both sofia and maria, both of which are wrong results for a username lookup. Use strcmp() for comparisons.
Try something more like this instead:
#include <stdio.h>
#include <string.h>
#define N 8
char* username[N] = {"ana", "sofia", "maria", "isabel", "joao", "hugo", "francisco", "pedro"};
char str[20] = {0};
void read_username()
{
printf("Insert your username: ");
if (fgets(str, 20, stdin))
{
int len = strlen(str);
if ((len > 0) && (str[len-1] == '\n'))
str[len-1] = '\0';
}
}
void searchusername()
{
for(int i = 0; i < N ; i++)
{
if (strcmp(username[i], str) == 0)
{
printf("username exists");
return;
}
}
printf("username does not exist");
}
int main()
{
read_username();
searchusername();
}

Your compare failed because of the '\n' character.
When using gets and fgets you should trim the input.
You can use function like this:
#include <ctype.h> //for isspace
char* trim(char *input_string)
{
int i=0;
char *retVal = input_string;
i = strlen(input_string)-1;
while( i>=0 && isspace(input_string[i]) ){
input_string[i] = 0;
i--;
}
i=0;
while(*retVal && isspace(retVal[0]) ){
retVal ++;
}
return retVal;
}

Related

How to make a function to input a string with unknown length in c with type void

I am trying to make a function that input an unknown length of a string , but I don't want it to return anything I want it to make changes by using the pointer that I pass.
this was my attempt .
#include <stdlib.h>
#include <stdio.h>
void get(char * string){
int size=1;
string = malloc(size);
char c;
int i=0;
while(1){
c = getchar();
if(c=='\n'){break;}
string[i] = c;
i++;
string = realloc(string , ++size);
}
string[i] = '\0';
}
int main(){
char *buff;
printf("String :");
get(buff);
printf("%s" , buff);
return 0;
}
the output on my gcc windows os :
PE
1- what is the PE
2- what is wrong here
3- is the c=='\n' line good for the test if the user pressed an enter or should i use EOF or something else
I made a few changes to your code so that it would use the pointer passed to it and handle a possible EOF in the input:
#include <stdlib.h>
#include <stdio.h>
void get(char **string){
char *input = NULL;
int result, index = 0;
while (1) {
result = getchar();
if (EOF == result) { printf("\n"); break; }
if ('\n' == result) break;
char *temp = realloc(input , index + 2);
if (NULL == temp) {
perror("Could not increase memory for string");
if (input) free(input);
exit(1);
}
input = temp;
input[index++] = (char) result;
}
if (input) {
input[index] = '\0';
*string = input;
}
}
int main(void) {
char *buff = NULL;
printf("String : ");
get(&buff);
if (buff) {
printf("%s\n" , buff);
free(buff);
}
return 0;
}
Output
$ ./main
String : a short string
a short string
$ ./main
String : input with EOF
input with EOF
Note
I do my best to handle error conditions, but I am not certain I caught everything.

I am having issues with the get_string function

I just finally got the cs50 library working after a lot of trial on my Windows Vscode. Now, the problem is that the get_string function would not work as used below:
int main(void)
{
string s = get_string("Enter string: ");
// ensure string was read
if (s == NULL)
{
return 1;
}
string next = get_string("You just entered %s. Enter a new string: ", s);
if (next == NULL)
{
return 1;
}
printf("Your last string was %s\n", s);
}
When I write
string name = get_string("Give me a name:");
I get the error
In file included from hello.c:1:0:
cs50.c:78:8: note: expected ‘char **’ but argument is of type ‘char *’
string get_string(va_list *args, const string format, ...)
^~~~~~~~~~
hello.c:10:16: error: too few arguments to function ‘get_string’
string name = get_string("Give me a name:");
^~~~~~~~~~
In file included from hello.c:1:0:
cs50.c:78:8: note: declared here
string get_string(va_list *args, const string format, ...)
Here is my code. I am basically testing the get_string function not necessary needed in the function.
#include "cs50.c"
#include "cs50.h"
#include <stdio.h>
#include <stdlib.h>
int main()
{
char str[20] = "#";
string name = get_string("Give me a name:");
printf("What height of pyramid \n");
int user;
if(scanf("%d", &user))
{
for (int i =0; i< 8; i++)
{
if(user <= 0 || user > 8 )
{
printf("Height: %d \n", user);
printf("Provide value between 1 and 8 \n");
scanf("%d", &user);
}
}
printf("\n");
int i;
for (i = 1; i <= user; i++) {
for(int k = user; k > i; k--){
putchar(' ');
}
int j;
for (j = 0; j < i; j++) {
putchar('#');
}
putchar('\n');
}
return EXIT_FAILURE;
}
}
I expect to write
string s = get_string("Enter string: ");
and get a prompt in the terminal when running the code.
I was able to get through this by including cs50.h and cs50.c from libcs50-8.0.3 which is the v8.0.3 that conform with what I want.
Everything is fine now.
In fact by trial and error did not bring you quite to the correct solution.
The problem is rather simple. The get_string you're supposed to use is a macro from cs50.h. The cs50.c removes this macro definition and defines another function by name get_string (yes, it is awful). The end result is that you cannot #include <cs50.c> to make the code work even in a single-file application.
What you need to do is to only
#include <cs50.h>
and add cs50.c as another translation unit in your project, i.e. if your main program is prog.c you will add cs50.c as a file in the same folder.
If you added cs50 library and even you get this error, I can give an advice like this:
For linux terminal;
clang -o file_name file_name.c -lcs50
source: Harvard College CS50
Copy and paste this code in your source code file:
My Own CS50 Get_String Function (Shortened Implementation)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#define SIZE_MAX 50
char *get_string(const char *format, ...)
{
if (format != NULL)
{
va_list ap;
va_start(ap, format);
vprintf(format, ap);
va_end(ap);
}
char *buffer = NULL;
size_t capacity = 0;
size_t size = 0;
unsigned read = 0;
int c;
while ((c = fgetc(stdin)) != '\r' && c != '\n' && c != EOF)
{
read++;
if (read > capacity && read < SIZE_MAX )
capacity++;
else
{
free(buffer);
return NULL;
}
char *temp = realloc(buffer, capacity);
if (temp == NULL)
{
free(buffer);
return NULL;
}
buffer = temp;
buffer[size++] = c;
}
if (size == 0 || c == '\n')
return NULL;
if (size == SIZE_MAX)
{
free(buffer);
return NULL;
}
char *s = realloc(buffer, size + sizeof(char));
if (s == NULL)
{
free(buffer);
return NULL;
}
s[size] = '\0';
return s;
}
This works for me:
#include <cs50.c>
#include <stdio.h>
int main(void)
{
char c1 = ' ', *c2, **c3;
c2 = &c1;
c3 = &c2;
string s = get_string(c3, "Some text: ");
printf("%s\n", s);
}
I got a workaround to this problem! Calling the string 's' variable within the 'get_string' function fixes this problem.
#include <cs50.c>
#include <cs50.h>
#include <stdio.h>
int main(void)
{
printf("Enter a string: ");
string s = get_string(" ", s);
printf("%s", s);
Note:
Am not aware if this approach results into bugs down the line. It works fine for me.

how to check for numbers in a certain position in a string and extracting its value in c?

I'm supposed to write a function not using other libraries but that gets a string from a user (up to 100 chars). the string would be in this form: a,b,c,d,x,y,z etc... from which i'm supposed to extract only the first whole numbers in between commas to a different array.
so for example let's say i get this as an input: abcd,32,23.5,4,6,hf3,45g,2
the numbers in the new array should be: 32,4,6,2 because these are the first 4 numbers you can see in the input. if there was no number found the default value will be 0.
this is what i've been doing so far, but somehow it doesn't seem to be right,
the idea was to check each char seperately, and unless a comma was seen and the char is between the ASCII value of '0' and '9' to sum them. if a different char was seen before the comma, then "skip" will get the value 1, this way the function will keep looking for another number.
thanks for the help.
int getParameters()
{
char input[100];
int parameters[4]={0};
int indexInput=0, indexParameters;
int charValue=0;
int skip=1;
scanf("%s", input);
for (indexParameters=0; indexParameters<4;skip=0)
{
if (input[indexInput]=='\0')
break;
else
{
for (;input[indexInput]!=','; ++indexInput)
{
printf("%c\n", input[indexInput]);
if(input[indexInput]=='\0')
break;
else if (input[indexInput]<'9' &&
input[indexInput]>'0')
{
charValue=input[indexInput]-'0';
parameters[indexParameters]*=10;
parameters[indexParameters]+=charValue;
}
else
{
skip=1;
}
}
}
indexInput++;
if (input[indexInput]==",")
skip==1;
if (skip==1)
{
parameters[indexParameters]=0;
}
else
indexParameters++;
}
return 0;
}
sample by strtok and strtol
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(){
char input[100] = "abcd,32,23.5,4,6,hf3,45g,2";
char *token = strtok(input, ",");
while(token){
char *endp;
int num = strtol(token, &endp, 10);
if(*endp == '\0')
printf("%d\n", num);
//else //not integer.
token = strtok(NULL, ",");
}
return 0;
}
without strtok
#include <stdio.h>
#include <stdlib.h>
int main(){
char input[100] = "abcd,32,23.5,4,6,hf3,45g,2";
char *p = input;
while(*p){
char *endp;
int num = strtol(p, &endp, 10);
if(*endp == ',' || *endp == '\0')
printf("%d\n", num);
//else //not integer.
//skip to next read point
p = endp;
while(*p != ',' && *p)
++p;
if(*p)
++p;
}
return 0;
}
solved the problem, tried a different algorithm just with one loop:
int getParameters()
{
char input[100];
int parameters[4]={0};
int indexInput=0, indexParameters=0;
int skip=0, numberSeen=0;
scanf("%s", input);
for (;input[indexInput]!='\0' && indexParameters<4;++indexInput)
{
if (input[indexInput]==',' && skip==1)
{
parameters[indexParameters]=0;
skip=0;
}
else if (input[indexInput]==','&& numberSeen==1)
{
numberSeen=0;
indexParameters++;
}
else if (input[indexInput]==',')
continue;
else if (input[indexInput]<='9' && input[indexInput]>='0')
{
parameters[indexParameters]*=10;
parameters[indexParameters]+=input[indexInput]-'0';
numberSeen=1;
}
else
skip=1;
}
return 0;
}

C fgets and sscanf in loop : prevent useless looping

I have a problem with looping and fgets and sscanf to get the input.
I know to problem is from the size of the malloc with the input. If the user enter number larger than the malloc i want to ask again to enter a new number.
But in this code, if an user enter a too large number, it's looping lot of time (size of the word / 8) i think.
How to ask again to the user to enter new number without looping 4 times for example.
See the example i made with big number.
The idea was to free the input after the loop but it's doesn't works. Any ideas ?
There is my code :
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <stdbool.h>
#include <string.h>
int main(void) {
char x[8];
char y[8];
int result = 0;
char *input=malloc(sizeof(char)*8);
bool answer = 0;
char *pos;
while(!answer) {
fgets(input, sizeof(input)-1, stdin);
//remove the /n from fgets
if ((pos=strchr(input, '\n')) != NULL)
*pos = '\0';
result = sscanf (input, "%s %s", x, y);
printf("%d\n", result);
if(result < 2) {
fprintf(stderr, "There is an error with the number you give, try again\n");
} else {
printf("%s\n", x);
printf("%s\n", y);
}
}
return 0;
}
And the output for : "01 01"
01 01
2
01
01
Output for : 000000005 000000005
0000000000005 000000000000005
1
There is an error with the number you give, try again
1
There is an error with the number you give, try again
2
5
0000
1
There is an error with the number you give, try again
1
There is an error with the number you give, try again
fgets() doesn't throw away the rest of the line when it's longer than its buffer. You have to do it yourself.
If you look at this code I frequently use with fgets, you'll see the two tasks separated, and in which circumstances which one is done:
/*Returns 0 if OK, a negative value if EOF.*/
int fpurge(FILE *f)
{
int c;
while((c=fgetc(f))!=EOF && c!='\n')
{ }
return (c==EOF ? -1 : 0);
}
/* Returns a nonzero value if found, zero if not. */
int truncate_newline(char *str)
{
int bRet=0;
if(str!=NULL)
{
char *pNewLine = strchr(str, '\n');
if(pNewLine!=NULL)
{
bRet = 1;
*pNewLine = '\0';
}
}
return bRet;
}
/* Returns 0 if buffer is full, a positive value if line is complete,
a negative value if EOF (implies buffer full). */
int fclean(char *str, FILE *f)
{
int ret = 1;
if(!truncate_newline(str))
ret = fpurge(f);
return ret;
}
You can see that your own code does the truncate_newline part, but not the "throw away the rest of the line" (here in the function fpurge) part.
If you change your code thusly, it should work:
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <stdbool.h>
#include <string.h>
#define BUFFER_SIZE 8
int main(void) {
char x[BUFFER_SIZE];
char y[BUFFER_SIZE];
int result = 0;
char *input=calloc(BUFFER_SIZE, sizeof(char));
bool answer = 0;
char *pos;
while(!answer) {
fgets(input, BUFFER_SIZE, stdin);
//remove the /n from fgets
if ((pos=strchr(input, '\n')) != NULL)
*pos = '\0';
else
{
int c;
while((c=getchar())!='\n' && c!=EOF) {}
}
result = sscanf (input, "%s %s", x, y);
printf("%d\n", result);
if(result < 2) {
fprintf(stderr, "There is an error with the number you give, try again\n");
} else {
printf("%s\n", x);
printf("%s\n", y);
}
}
return 0;
}
Or simply replace the whole if() with fclean(input, stdin);

Updating string until period is found in C

In this function I am going to be receiving char * words such as
person.vet.blah
and
word.friends.joe
I want to extract the first word. So for the first one I want to extract
person
and the second one I want to extract
word
How can I correctly do this? Here is my code:
char *separate_name(char *machine_name)
{
//iterate until you find period. then return
char absolute_name[1000];
int i;
for (i =0; i < strlen(machine_name); i++)
{
if (machine_name[i] == '.')
absolute_name[i] = machine_name[i];
}
return absolute_name;
}
This is just segfaulting. Any ideas what I should be doing? machine_name is going to be the "person.vet.blah" and then return absolute_name which would be "person"
Fixing your code
As others have pointed out, you can't use absolute_name outside of the function in which it was defined. This is because you're when you return the variable from your function, all that is being returned is a pointer to the beginning of the array. Outside the function, the array itself no longer exists, so the pointer is invalid and you get a segfault if you try and dereference it.
You can get around this by using malloc. Don't forget to free the memory you have allocated when you are done using it.
By the way, as well as changing your loop to a while, I also fixed the check (you were checking machine_name[i] == '.', the opposite to what you wanted).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *separate_name(char *machine_name)
{
// allocate memory on the heap
char *absolute_name = malloc(strlen(machine_name)+1);
int i = 0;
while (i < strlen(machine_name) && machine_name[i] != '.') {
absolute_name[i] = machine_name[i];
++i;
}
absolute_name[i] = '\0';
return absolute_name;
}
int main()
{
char name1[] = "person.vet.blah";
char *first1 = separate_name(name1);
if (first1 != NULL) {
printf("%s\n", first1);
free(first1);
}
char name2[] = "word.friends.joe";
char *first2 = separate_name(name2);
if (first2 != NULL) {
printf("%s\n", first2);
free(first2);
}
return 0;
}
A better alternative
strtok is the perfect tool for the job:
#include <stdio.h>
#include <string.h>
char *separate_name(char *machine_name)
{
return strtok(machine_name, ".");
}
int main()
{
char name1[] = "person.vet.blah";
char *first1 = separate_name(name1);
if (first1 != NULL) printf("%s\n", first1);
char name2[] = "word.friends.joe";
char *first2 = separate_name(name2);
if (first2 != NULL) printf("%s\n", first2);
return 0;
}
As pointed out in the comments (thanks #John), strtok modifies the string that is passed to it (it replaces the delimiter . by the \0 null byte to mark the end of the string). This isn't a problem here but is something to be aware of.
Output using either program:
person
word
#include <stdio.h>
char *separate_name(const char *machine_name){
static char absolute_name[1000];
int i;
for (i =0; i < sizeof(absolute_name)-1 ; i++){
if(machine_name[i] == '.' || machine_name[i] == '\0'){
absolute_name[i] = '\0';
break;
} else {
absolute_name[i] = machine_name[i];
}
}
return absolute_name;
}
int main(void){
printf("%s\n", separate_name("person.vet.blah"));
printf("%s\n", separate_name("word.friends.joe"));
return 0;
}

Resources