Comparing characters in C - c

I have a question about comparing a single char of a string in C inside a function.
The code looks like this:
int fq(char *s1){
int i;
for(i=0;i<strlen(s1);i++){
if(s1[i]=="?"){
printf("yes");
}
}
return 1;
}
Even if s1="???" it never prints out yes. I have managed to solve the problem but i am curious as to why it works one way but not the other.
This is the piece of code that works:
int fq(char *s1,char *s2){
int i;
char q[]="?";
for(i=0;i<strlen(s1);i++){
if(s1[i]==q[0]){
printf("yes");
}
}
return 1;
}

Because the first sample compares addresses instead of characters.
There is no string type in c and the == operator when applied to an array or a pointer, compares the addresses instead of the contents.
Your function would be correctly written like this
int fq(char *s1,char *s2)
{
int i;
for (i = 0 ; s1[i] ; ++i)
{
if (s1[i] == 'q')
printf("yes");
}
return 1;
}
you can compare s1[i] to 'q'.

"?" Isn't a char but a string with just one char
'?' Is a char and should return true in s1[i] == '?'

if(s1[i]=="?"){
is not the right syntax to check whether s1[i] is the character '?'. It needs to be:
if(s1[i] == '?'){
You might want to investigate how you can change your compiler settings so that you get warnings when such expressions exist in your code base.
Using the option -Wall with gcc, I get the following message:
cc -Wall soc.c -o soc
soc.c: In function ‘fq’:
soc.c:7:15: warning: comparison between pointer and integer
if(s1[i]=="?"){
^
soc.c:7:15: warning: comparison with string literal results in unspecified behavior [-Waddress]

In C character array i.e. string has syntax as "". For a single character the syntax is ''.
In your case: it should be: if(s1[i]=='?')
If you want to compare it in string form you need to strcmp. Because the '==' operator is not capable to compare strings in C.
To compare two strings we can use: if(!strcmp(s1,q))
And for this operation you need to add string.h header like: #include <string.h>
To compare strings with '==' operator you need to overload the operator. But, C does not support operator overloading. To do so you can use C++ language.

Related

Program keeps returning Segmentation Fault [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I'm a new person who loves to play around with coding. Recently I was going through a course on edx, and one of the exercises I need to complete has this small code snippet that keeps on giving Segmentation fault. I have taken out the faulty bit (everything else compiles nicely)
#include <stdio.h>
#include <string.h>
#include <cs50.h>
#include <ctype.h>
#include <stdlib.h>
int main (int argc, string argv[])
{
if (argc == 2 && isalpha(argv[1]))
{
int a = 0;
while (argv[1][a] == '\0')
{
a++;
printf("%c\n", argv[1][a]);
}
}
else
{
printf("Usage: ./programname 1-alphabetical word\n");
return 1;
}
}
The problem seems to be here: argv[1][a] but I can't for the life of me find out what, and how to fix it.
(1) isalpha(argv[1]) is wrong. This function expects a single character, but you are passing a pointer-to-string. That will certainly not give you any kind of expected result, and it's probably Undefined Behaviour into the bargain. You either need to loop and check each character, use a more high-level library function to check the entire string, or - as a quick and probably sense-changing fix - just check the 1st character as BLUEPIXY suggested: isalpha( argv[1][0] ) or isalpha( *argv[0] ).
(2) Your while condition is wrong. You are telling it to loop while the current character is NUL. This will do nothing for non-empty strings and hit the next problem #3 for an empty one. You presumably meant while (argv[1][a] != '\0'), i.e. to loop only until a NUL byte is reached.
(3) You increment index a before trying to printf() it. This will index out of range right now, if the input string is empty, as the body executes and then you immediately index beyond the terminating NUL. Even if the loop condition was fixed, you would miss the 1st character and then print the terminating NUL, neither of which make sense. You should only increment a once you have verified it is in-range and done what you need to do with it. So, printf() it, then increment it.
2 and 3 seem most easily soluble by using a for loop instead of manually splitting up the initialisation, testing, and incrementing of the loop variable. You should also use the correct type for indexing: in case you wanted to print a string with millions or billions of characters, an int is not wide enough, and it's just not good style. So:
#include <stddef.h> /* size_t */
for (size_t a = 0; argv[1][a] != '\0'; ++a) {
printf("%c\n", argv[1][a]);
}
isalpha(argv[1]) looks incorrect and should probably be isalpha(argv[1][0])
isalpha takes a character but you entered in a string to the function
another thing that sticks out as wrong is argv[1][a] == '\0' the ==
should be != this will mean that the while loop will stop once it hits the \0
perhaps
if (argc == 2)
{
int a = 0;
while (argv[1][a] != '\0')
{
if (isalpha(argv[1][a])
printf("%c\n", argv[1][a]);
a++;
}
}
may be what you are looking for?
The only reason for the segmentation fault I see is this subexpression of the if statement
if (argc == 2 && isalpha(argv[1]))
^^^^^^^^^^^^^^^^
There is specified an argument of an incorrect type. The expression argv[1] has the type char * while the function requires an object of character type that is interpreted as unsigned char and promoted to the type int.
So when the promoted argument has a negative value (except the EOF value) the function isalpha has undefined behavior.
From the C Standard (7.4 Character handling <ctype.h>)
1 The header <ctype.h> declares several functions useful for
classifying and mapping characters.198) In all cases the argument is
an int, the value of which shall be representable as an unsigned
char or shall equal the value of the macro EOF. If the argument has
any other value, the behavior is undefined.
You should write the if statement either like
if (argc == 2 && isalpha( ( unsigned char )argv[1][0] ) )
or like
if (argc == 2 && isalpha( ( unsigned char )*argv[1] ) )
Also there is a bug in the while statement that will execute never if the argument is not an empty string. I think you mean the following
int a = 0;
while ( argv[1][a] != '\0' )
{
printf("%c\n", argv[1][a]);
a++;
}
or for example like
int a = 0;
while ( argv[1][a] )
{
printf("%c\n", argv[1][a++]);
}

comparing getchar with a character returns a warning and gives me the wrong code

i'm having a problem with comparisons using getchar() and file redirection.
I have a code that resembles this:
char result = getchar(); // getchar returns the next char in the file
int linecount = 0;
if (result == "\n") {
linecount++;
}
But I get a warning when compiling it. It says that I can't compare an int with a pointer, but from my understanding, result is a char and so is "\n", so I'm really confused. I can also use printf("%c", result") and it works fine, implying that result is a char. Does anyone know why I'm getting this error? Thanks! Also, running the code, linecount will always return 0 even if the first character in the file I'm using as my input is a newline.
You are comparing a char with a char *, that is, a string. "" (doublequoted) values are treated as strings in C, so your code should be
if (result == '\n') {
linecount++;
}
Alternatively, you could use strcmp or strncmp with the char casted to a pointer, but that's not necessary.
Do note that the size of a char is less than an int so the conversion from a char to int doesn't make you lose anything.

Searching for an element in 2D array, C programming

I'm a noob at C programming and I'm having some difficulties making a string list and searching for a specific element.
#include <stdio.h>
#include <string.h>
# define MAX 6
int main(){
char word[MAX];
char x[MAX][20];
int i;
strcpy(x[0], "One");
strcpy(x[1], "Two");
strcpy(x[2], "Three");
strcpy(x[3], "Four");
strcpy(x[4], "Five");
strcpy(x[5], "Six");
printf("%s", "Search:");
scanf("%s", word);
for (i=0; i<6; i++) {
if (x[i] == word) {
printf("%s", "Found a match!");
}
}
return 0;
}
It's never executing the statement present in the if block (i.e, printf("Found a match!")) . Any idea why it is not executing the above mentioned statement?
Thanks!
Use
if(strcmp(x[i],word) == 0)
printf("Found match\n");
== can't be used to compare strings as you are doing it.
This only compares the pointers and not the strings
It never returns "Found a match!". Any idea why?
Reason:
In C, array names are converted to pointers to their first elements ( with some exceptions there). x[i] == word is comparing two pointers instead of comparing strings. Since the base addresses of both arrays are different, comparison returns a false value.
Correction:
Use strcmp to compare two strings.
This
if (x[i] == word)
should be
if (strcmp(x[i], word) == 0)
In c a predefined function is present in string.h library it is strcmp as stated by other users function int strcmp(const char *str1, const char *str2) compares the string pointed to bystr1 to the string pointed to by str2.u can write your own function for comparing strings and use it.
I want you to conceptually understand why we can't use == in c unlike c++ as c don't contain anything like string class(c is purely procedural) so that u can create object of it and use it.hence c uses char array to represent a string .if u examine ur code x[i] == word compares starting addresses of char arrays/strings x[i],word. I believe u understood the concept . now I want to explain that u can use pointers here i.e
if (*x[i] == *word)
printf("Found a match!");
Works fine as u can understand that here we are comparing two strings directly by pointing to their address locations.sorry if I have provided unwanted info due to my inexperience in SO as this my first answer in SO.
use strcmp() function for comparing two string. when two string is match its result is 0.
so you can change like :
if ( ! strcmp(word,x[i]) ) // when match result will be `! 0 = 1`
printf("Found Match\n");
in the C programming language, the == operator is not working for comparing strings(as others wrote before me). I advice to try using a really nice feature in C++ called string. It is builded in the standard library, and with this, you can use the == operator for comparing.
#include <iostream>
using namespace std;
int main(void)
{
string a = "Apple";
if( a == "Apple" ) cout << "This is working" << endl;
}

Reading character by character from a file in C

I wrote the following program :
int main(){
char str[500],c;
FILE *f1=fopen("input.txt","r");
FILE *f2=fopen("output.txt","w");
while(c=fgetc(f1)!=EOF)
fputc(toupper(c),f2);
fclose(f1);
}
I was not getting the desired result though.
I rewrote the code using a do while loop.
int main(){
char str[500];
FILE *f1=fopen("input.txt","r");
FILE *f2=fopen("output.txt","w");
char c;
do
{
fputc(toupper(c),f2);
c=fgetc(f1);
}while(c!=EOF);
}
I figured out that the reason the first code fails is because in the while loop
while(c=fgetc(f1)!=EOF), we cannot guarantee that the left part of != is evaluated first and hence the results are not proper. Is this correct the explanation?
Yes you are correct; in your first code your while loop is written wrongly:
while(c=fgetc(f1)!=EOF)
Should be:
while((c=fgetc(f1))!=EOF)
// ^ ^ added parenthesis
Because the precedence of operator != is greater than = operator in conditional expression c=fgetc(f1)!=EOF, the first returned the result of comparing the value from fgetc() with EOF (either 0 or 1) and assigned that to c. (That means simply c=fgetc(f1)!=EOF expression is equivalent to c=(fgetc(f1)!=EOF) and this is not what you need.)
You need () to overwrite precedence as I suggested.
But you have second thing to improve that is c variable must be an int (not char) in order to hold an EOF-value.
A very good Read: Definition of EOF and how to use it effectively
I will add a little why c should be int, not char. Suppose you write
#include <stdio.h>
#include <ctype.h>
#include <locale.h>
int main(){
setlocale(LC_ALL,"");
FILE *f1=fopen("input.txt","r");
FILE *f2=fopen("output.txt","w");
char c;
while(EOF != (c=fgetc(f1))){
if(isalpha(c)) c = toupper(c);
fputc(c,f2);
}
return 0;
}
And your input.txt is
some text
Некоторый текст
Ъ - on this letter program will stop
in KOI8-R symbol Ъ have code 255 == -1 (when you use char).
That's why in case of using char instead of int will give your output.txt with only that text:
SOME TEXT
НЕКОТОРЫЙ ТЕКСТ
As for non-working code with parentheses: c=fgetc(f1)!=EOF could be denote by compiler as c = (fgetc(f1)!=EOF), that's why it's better always to add parentheses.
I recommend you to use flags -Wall -Werror when compiling your applications. In that case "forgetting" of parentheses would give you an error:
11.c: In function 'main':
11.c:9:2: error: suggest parentheses around assignment used as truth value [-Werror=parentheses]
cc1: all warnings being treated as errors

Warning: comparison is always true due to limited range of data type

I'm testing this function that's supposed to read input from the user but it throws me a segmentation fault
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAX_STRING_LENGTH 10
int
readinput(char *input)
{
int c;
int i=0;
while((c=getchar()) != EOF && c != '\n') //Here is where the warning occurs.
{
input[i]=c;
i++;
}
input[i]=0;
if(strlen(input)>0)
{
if(isalpha(input[0]) && input[1]=='-' && isalpha(input[2]) && strlen(input)==3)
return 0;
else if(!strcmp(input, "quit"))
return 1;
else if(!strncmp(input, "save ", 5))
return 2;
else if(!strcmp(input, "undo"))
return 3;
}
return -1;
}
int main()
{
char *str;
printf("write a string\n");
int nr=readinput(str);
printf("%d\n", nr);
printf("%s\n", str);
return 0;
}
I did notice the stupid error I made, but still, segmentation fault, why?
This is because EOF is defined (in my compiler) as -1 and char is unsigned byte. so it is always !=
c != '/n' is wrong
change it to
c != '\n'
c != '/n' should be c != '\n'
\ is an escape character which indicates, in the case where it is followed by n, a newline. /n will be treated as two distinct characters, which cannot properly be compared to a single char variable.
As for you segmentation fault, you'll need to allocate some space for str in your main function:
char* str = malloc(sizeof(char)*MAX_STRING_LENGTH);
or
char str[MAX_STRING_LENGTH];
but you'll also have to ensure you don't try to read a string that has more characters than your str array can hold.
It faults because you never allocated space for str and it points to a random location which causes readinput to try to store data in a place that doesn't exist.
The segmentation fault arises because you've passed an uninitialized pointer to the function readinput(). You need to do something like:
char str[4096];
int nr = readinput(str);
You should pass in a length of the array so that the called code can verify that it does not overflow its boundaries. Or you can live dangerously and decide that 4096 is big enough, which it probably will be until someone is trying to break your program deliberately.
The original compiler warning was because the multi-character constant '/n' has a value (of type int) which is outside the range of values that can be stored in a char, so when c is promoted to int, the != comparison with the (implementation-defined) value of '/n' is bound to be true. Hence the warning:
Warning: comparison is always true due to limited range of data type
All multi-character character constants have implementation-defined values. There are no portable multi-character character constants.
ISO/IEC 9899:2011 §6.4.4.4 Character constants
¶10 ... The value of an integer character constant containing more than one character (e.g.,
'ab'), or containing a character or escape sequence that does not map to a single-byte
execution character, is implementation-defined. ...

Resources