in one of my university assignments I am restricted in the libraries I use. I am new to C and pointers and want to see if two strings (or should I say char's) are equal.
Part of me wants to loop through every char of the 'char string' and test equivalence, but then it comes back how to test equivalence (lol).
Any help is appreciated.
edit: I am seeing this:
warning: result of comparison against a string literal is
unspecified (use strncmp instead) [-Wstring-compare]
which leads to a segmentation fault. I know it has to do with this piece of code because all I added was:
if (example.name == "testName"){
printf("here!\n");
}
Part of me wants to loop through every char of the 'char string' and test equivalence
That's exactly what you need to do. Make a function mystrcmp with the signature identical to regular strcmp,
int mystrcmp ( const char * str1, const char * str2 );
and write your own implementation.
but then it comes back how to test equivalence.
When you loop character-by-character, you test equivalence of individual characters, not strings. Characters in C can be treated like numbers: you can compare them for equality using ==, check what character code is less than or greater than using < and >, and so on.
The only thing left to do now is deciding when to stop. You do that by comparing the current character of each string to zero, which is the null terminator.
Don't forget to forward-declare your mystrcmp function before using it.
A string in C is terminated with null character(0x00 or \0).You should compare both strings in a loop character by character till null char for either of the string is reached.
Loop should be broken if characters are not equal.
EDIT:
To answer your edit in question:
You should take two character pointers pointing to both strings and then copmare them like
//loop start,loop till null for any one of the string is found
if(*ptr1 != *ptr2)
{
//break loop
}
ptr1++;ptr2++;
//end loop
if((*ptr1 == *ptr2) &&(*ptr1== 0x00))
{
//strings are equal
}
Given that this is a university assignment, you should pay heed to chars just being small integers. You should also pay heed that C strings are contiguous memory buffers terminated by a binary zero (0x00).
You should also learn about pointer math. You will learn ways to shorten the code you have to write while learning something really interesting concerning the C language and how computers work. It will certainly help you if you choose a career on lower-level programming.
Related
int count_words(string word)
{
string spaces = "";
int total_words = 1;
int i, j = 0 ;
for (i = 0; i < strlen(word); i++)
{
strcpy(spaces, word[i]);
if (strcmp(spaces, " ") == 0)
{
total_words = total_words + 1;
}
}
return total_words;
}
I am trying to make a function in c that gets the total number of words, and my strategy is to find the number of spaces in the string input. However i get an error at strcpy about integer to ptrtype conversion,. I cant seem to compare the 2 strings without getting the error. Can someone explain to me whats how the error is happening and how I would go about fixing it. The IDE is also suggesting me to add an ampersand beside word[i] but it then makes a segmentation fault output
You need to learn a little more about the distinction between characters and strings in C.
When you say
strcpy(spaces, word[i]);
it looks like you're trying to copy one character to a string, so that in the next line you can do
if (strcmp(spaces, " ") == 0)
to compare the string against a string consisting of one space character.
Now, it's true, if you're trying to compare two strings, you do have to call strcmp. Something like
if (spaces == " ") /* WRONG */
definitely won't cut it.
In this case, though, you don't need to compare strings. You're inspecting your input a character at a time, so you can get away with a simple character comparison instead. Get rid of the spaces string and the call to strcpy, and just do
if (word[i] == ' ')
Notice that I'm comparing against the character ' ', not the string " ". Using == to compare single characters like this is perfectly fine.
Sometimes, you do have to construct a string out of individual characters, "by hand", but when you do, it's a little more elaborate. It would look like this:
char spaces[2];
spaces[0] = word[i];
spaces[1] = '\0';
if (strcmp(spaces, " ") == 0)
...
This would work, and you might want to try it to be sure, but it's overkill, and there's no reason to write it that way, except perhaps as a learning exercise.
Why didn't your code
strcpy(spaces, word[i]);
work? What did the error about "integer to pointer conversion" mean? Actually there are several things wrong here.
It's not clear what the actual type of the string spaces is (more on this later), but it has space for at most 0 characters, so you're not going to be able to copy a 1-character string into it.
It's also not clear that spaces is even writable. It might be a constant, meaning that you can't legally copy any characters into it.
Finally, strcpy copies one string to another. In C, although strings are arrays, they're usually referred to as pointers. So strcpy accepts two pointers, one to the source and one to the destination string. But you passed it word[i], which is a single character, not a string. Let's say the character was A. If you hadn't gotten the error, and if strcpy had tried to do its job, it would have treated A as a pointer, and it would have tried to copy a string from address 65 in memory (because the ASCII value of the character A is 65).
This example shows that working with strings is a little bit tricky in C. Strings are represented as arrays, but arrays are second-class citizens in C. You can't pass arrays around, but arrays are usually referred to by simple pointers to their first element, which you can pass around. This turns out to be very convenient and efficient once you understand it, but it's confusing at first, and takes some getting used to.
It might be nice if C did have a built-in, first-class string type, but it does not. Since it does not, C programmers myst always keep in mind the distinction between arrays and characters when working with strings. That "convenient" string typedef they give you in CS50 turns out to be a bad idea, because it's not actually convenient at all -- it merely hides an important distinction, and ends up making things even more confusing.
This question already has answers here:
Issue with main arguments handling
(3 answers)
Closed 7 years ago.
I am fairly new to C, so am not overly familiar with it's syntax, however I have debugged my code and researched for the correct syntax, and it seems to be correct, I have also changed the scope of the variables to see if this was causing the error.
The if statement should compare two variables, which both hold strings, I have even printed both the variables out to ensure they are the same, however it is still skipping straight to the else section of the if statement. Can anyone give me any pointers on why it will not run the if statement, it just skips straight to 'incorrect'.
The correctWord variable is defined at a different section in the code.
Find full code here.
-UPDATE-
I have now updated the syntax of the code, however it is still returning false.
char correctWord[20];
void userGuess(){
char userWordGuess[20];
printf("Anagram: ");
printf(anagramWord);
printf("Your Guess: ");
scanf("%s",userWordGuess); //Reads in user input
printf(correctWord);
printf(userWordGuess);
if(strcmp(userWordGuess, correctWord) == 0){
printf("Congratulations, you guessed correctly!");
}else{
printf("Incorrect, try again or skip this question");
}
}
You cannot compare strings in C using ==, because this compares the addresses of the strings, not the contents of the string. (which you certainly don't require, and obviously, the addresses of the two strings are not equal too.)
C has a pretty nice function for it : strcmp() which returns 0 if both the strings are equal.
Try using this in your if condition:
if (!strcmp(userWordGuess,correctWord))
{
//Yay! Strings are equal. Do what you want to here.
}
Be sure to #include <string.h> before using strcmp().
In C, you can't compare strings using ==. You will end up comparing the addresses of the strings, which is not the same.
You need to call the strmcp() function, which will return 0 if its arguments (two strings) are equal.
So the code should be if(strcmp(userWordGuess, correctWord) == 0).
You're comparing addresses of different arrays, which will always be unequal.
You need to use strcmp or some other strings library function to compare strings character by character.
userWordGuess == correctWord will compare the pointers (i.e. the locations in memory of the arrays), which are probably not equal.
For string comparision in C, use strcmp (or strncmp):
if (!strcmp(userWordGuess, correctWord)){
/*Strings are equal*/
Use
if(strcmp(userWordGuess, correctWord) == 0) // strings are equal
{
printf("Congratulations, you guessed correctly!");
}
else // not equal
{
printf("Incorrect, try again or skip this question");
}
if both string are equal than if condition will run. otherwise it wil run else
The strings are not first-class citizens in the C language. The strings are represented as either arrays of characters or pointers to such arrays.
In both cases, the variable you use to access the string is a synonym for the address in memory of the first character of the string.
What you compare with userWordGuess == correctWord is not the strings but their addresses in memory. Since userWordGuess and correctWord are two different arrays of characters, their addresses in memory are always different and their comparison will always produce FALSE.
In order to compare the actual string values you have to use the standard function strcmp() or one of its variants (find them at the bottom of the documentation page).
Change in the code:
/** Need to include the header that declares the strcmp() function */
#include <string.h>
char correctWord[20];
void userGuess(){
char userWordGuess[20];
/** stripped some lines here ... */
/** compare the strings, not their addresses in memory */
if (strcmp(userWordGuess, correctWord) == 0) {
/** the rest of your code */
What you are doing here is comparing two pointers. userWordGuess and correctWord point each to the beginning of an array of characters (which is what you defined at the beginning of your example code).
So if you want to compare the two arrays of chars you can use the strcmp function defined in string.h
It is important that you learn the relation between arrays and pointers. Pointer arithmetic is as well important here. Check this out: Arrays, Pointers, Pointer Arithmetic
char first_array[5][4] = {"aaa","bbb","ccc","ddd","eee"};
char second_array[1][4];
How would I copy, for example, the third element in first_array ("ccc") and save it to second_array?
The syntax below is clearly wrong, but this is what I'm asking for:
second_array[0] = first_array[2];
Also, after copying, I also want to know how to compare elements in the two arrays. Again, the syntax below might be wrong, I'm just explaining what I'm trying to do:
if(second_array[0] == first_array[2]){ printf("yes"); } //should print yes
You can't assign to arrays in c, you can fill arrays with some library functions like strcpy(), so
second_array[0] = first_array[2];
would be
strcpy(second_array[0], first_array[2]);
you must however ensure that the destination array fits the number of characters you are copying to it.
If you try to compare two strings in c, you can't do it through the == operator, because strings in c are arrays of char which contain a sequence of non-nul characters followed by a nul character, so if you write this
if (second_array[0] == first_array[2])
even when you succeeded at copying the data, the result will be most likely false, because you are not comparing the contents of the arrays, but their addresses, so to compare them correctly there is also a function strcmp() then the correct way of comparing the strings is
if (strcmp(second_array[0], first_array[2]) == 0)
The functions above require you to include the string.h header, and also that the passed strings are strings in the c sense, i.e what I described above.
I was recently trying to do this, as well: it is not possible to do this sort of direct assignment in C.
When you write first_array[0], the compiler will read that as an address which points to the first element (character) of first_array[2], not the entire string. When you run the assignment, if it were to work, it would only set the first character.
The easiest way is to use strncpy or memcpy (or a loop to cycle through the string.
I wrote this small piece of code in C to test memcmp() strncmp() strcmp() functions in C.
Here is the code that I wrote:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char *word1="apple",*word2="atoms";
if (strncmp(word1,word2,5)==0)
printf("strncmp result.\n");
if (memcmp(word1,word2,5)==0)
printf("memcmp result.\n");
if (strcmp(word1,word2)==0)
printf("strcmp result.\n");
}
Can somebody explain me the differences because I am confused with these three functions?
My main problem is that I have a file in which I tokenize its line of it,the problem is that when I tokenize the word "atoms" in the file I have to stop the process of tokenizing.
I first tried strcmp() but unfortunately when it reached to the point where the word "atoms" were placed in the file it didn't stop and it continued,but when I used either the memcmp() or the strncmp() it stopped and I was happy.
But then I thought,what if there will be a case in which there is one string in which the first 5 letters are a,t,o,m,s and these are being followed by other letters.
Unfortunately,my thoughts were right as I tested it using the above code by initializing word1 to "atomsaaaaa" and word2 to atoms and memcmp() and strncmp() in the if statements returned 0.On the other hand strcmp() it didn't. It seems that I must use strcmp().
In short:
strcmp compares null-terminated C strings
strncmp compares at most N characters of null-terminated C strings
memcmp compares binary byte buffers of N bytes
So, if you have these strings:
const char s1[] = "atoms\0\0\0\0"; // extra null bytes at end
const char s2[] = "atoms\0abc"; // embedded null byte
const char s3[] = "atomsaaa";
Then these results hold true:
strcmp(s1, s2) == 0 // strcmp stops at null terminator
strcmp(s1, s3) != 0 // Strings are different
strncmp(s1, s3, 5) == 0 // First 5 characters of strings are the same
memcmp(s1, s3, 5) == 0 // First 5 bytes are the same
strncmp(s1, s2, 8) == 0 // Strings are the same up through the null terminator
memcmp(s1, s2, 8) != 0 // First 8 bytes are different
memcmp compares a number of bytes.
strcmp and the like compare strings.
You kind of cheat in your example because you know that both strings are 5 characters long (plus the null terminator). However, what if you don't know the length of the strings, which is often the case? Well, you use strcmp because it knows how to deal with strings, memcmp does not.
memcmp is all about comparing byte sequences. If you know how long each string is then yeah, you could use memcmp to compare them, but how often is that the case? Rarely. You often need string comparison functions because, well... they know what a string is and how to compare them.
As for any other issues you are experiencing it is unclear from your question and code. Rest assured though that strcmp is better equipped in the general case for string comparisons than memcmp is.
strcmp():
It is used to compare the two string stored in two variable, It takes some time to compare them. And so it slows down the process.
strncmp():
It is very much similar to the previous one, but in this one, it compares the first n number of characters alone. This also slows down the process.
memcmp():
This function is used compare two variables using their memory. It doesn't compare them one by one, It compares four characters at one time. If your program is too concerned about speed, I recommend using memcmp().
To summarize:
strncmp() and strcmp() treat a 0 byte as the end of a string, and don't compare beyond it
to memcmp(), a 0 byte has no special meaning
strncmp and memcmp are same except the fact that former takes care of NULL terminated string.
For strcmp you'll want to be only comparing what you know are going to be strings however sometimes this is not always the case such as reading lines of binary files and there for you would want to use memcmp to compare certain lines of input that contain NUL characters but match and you may want to continue checking further lengths of input.
This might seem like a very simple question, but I am struggling with it. I have been writing iPhone apps with Objective C for a few months now, but decided to learn C Programming to give myself a better grounding.
In Objective-C if I had a UILabel called 'label1' which contained some text, and I wanted to run some instructions based on that text then it might be something like;
if (label1.text == #"Hello, World!")
{
NSLog(#"This statement is true");
}
else {
NSLog(#"Uh Oh, an error has occurred");
}
I have written a VERY simple C Program I have written which uses printf() to ask for some input then uses scanf() to accept some input from the user, so something like this;
int main()
{
char[3] decision;
Printf("Hi, welcome to the introduction program. Are you ready to answer some questions? (Answer yes or no)");
scanf("%s", &decision);
}
What I wanted to do is apply an if statement to say if the user entered yes then continue with more questions, else print out a line of text saying thanks.
After using the scanf() function I am capturing the users input and assigning it to the variable 'decision' so that should now equal yes or no. So I assumed I could do something like this;
if (decision == yes)
{
printf("Ok, let's continue with the questions");
}
else
{
printf("Ok, thank you for your time. Have a nice day.");
}
That brings up an error of "use of undeclared identifier yes". I have also tried;
if (decision == "yes")
Which brings up "result of comparison against a string literal is unspecified"
I have tried seeing if it works by counting the number of characters so have put;
if (decision > 3)
But get "Ordered comparison between pointer and integer 'Char and int'"
And I have also tried this to check the size of the variable, if it is greater than 2 characters it must be a yes;
if (sizeof (decision > 2))
I appreciate this is probably something simple or trivial I am overlooking but any help would be great, thanks.
Daniel Haviv's answer told you what you should do. I wanted to explain why the things you tried didn't work:
if (decision == yes)
There is no identifier 'yes', so this isn't legal.
if (decision == "yes")
Here, "yes" is a string literal which evaluates to a pointer to its first character. This compares 'decision' to a pointer for equivalence. If it were legal, it would be true if they both pointed to the same place, which is not what you want. In fact, if you do this:
if ("yes" == "yes")
The behavior is undefined. They will both point to the same place if the implementation collapses identical string literals to the same memory location, which it may or may not do. So that's definitely not what you want.
if (sizeof (decision > 2))
I assume you meant:
if( sizeof(decision) > 2 )
The 'sizeof' operator evaluates at compile time, not run time. And it's independent of what's stored. The sizeof decision is 3 because you defined it to hold three characters. So this doesn't test anything useful.
As mentioned in the other answer, C has the 'strcmp' operator to compare two strings. You could also write your own code to compare them character by character if you wanted to. C++ has much better ways to do this, including string classes.
Here's an example of how you might do that:
int StringCompare(const char *s1, const char *s2)
{ // returns 0 if the strings are equivalent, 1 if they're not
while( (*s1!=0) && (*s2!=0) )
{ // loop until either string runs out
if(*s1!=*s2) return 1; // check if they match
s1++; // skip to next character
s2++;
}
if( (*s1==0) && (*s2==0) ) // did both strings run out at the same length?
return 0;
return 1; // one is longer than the other
}
You should use strcmp:
if(strcmp(decision, "yes") == 0)
{
/* ... */
}
You should be especially careful with null-terminated string in C programming. It is not object. It is a pointer to a memory address. So you can't compare content of decision directly with a constant string "yes" which is at another address. Use strcmp() instead.
And be careful that "yes" is actually "yes\0" which will take 4 bytes and the "\0" is very important to strcmp() which will be recognized as the termination during the comparison loop.
Ok a few things:
decision needs to be an array of 4 chars in order to fit the string "yes" in it. That's because in C, the end of a string is indicated by the NUL char ('\0'). So your char array will look like: { 'y', 'e', 's', '\0' }.
Strings are compared using functions such as strcmp, which compare the contents of the string (char array), and not the location/pointer. A return value of 0 indicates that the two strings match.
With: scanf("%s", &decision);, you don't need to use the address-of operator, the label of an array is the address of the start of the array.
You use strlen to get the length of a string, which will just increment a counter until it reaches the NUL char, '\0'. You don't use sizeof to check the length of strings, it's a compile-time operation which will return the value 3 * sizeof(char) for a char[3].
scanf is unsafe to use with strings, you should alternatively use fgets(stdin...), or include a width specifier in the format string (such as "3%s") in order to prevent overflowing your buffer. Note that if you use fgets, take into account it'll store the newline char '\n' if it reads a whole line of text.
To compare you could use strcmp like this:
if(strcmp(decision, "yes") == 0) {
// decision is equal to 'yes'
}
Also you should change char decision[3] into char decision[4] so that the buffer has
room for a terminating null character.
char decision[4] = {0}; // initialize to 0
There's several issues here:
You haven't allocated enough storage for the answer:
char[3] decision;
C strings are bytes in the string followed by an ASCII NUL byte: 0x00, \0. You have only allocated enough space for ye\0 at this point. (Well, scanf(3) will give you yes\0 and place that NUL in unrelated memory. C can be cruel.) Amend that to include space for the terminating \0 and amend your scanf(3) call to prevent the buffer overflow:
char[4] decision;
/* ... */
scanf("%3s", decision);
(I've left off the &, because simply giving the name of the array is the same as giving the address of its first element. It doesn't matter, but I believe this is more idiomatic.)
C strings cannot be compared with ==. Use strcmp(3) or strncmp(3) or strcasecmp(3) or strncasecmp(3) to compare your strings:
if(strcasecmp(decision, "yes") == 0) {
/* yes */
}
C has lots of lib functions to handle this but it pays to know what you are declaring.
Declaring
char[3] decision;
is actually declaring a char array of length 3. So therefor attempting a comparison of
if(decision == "yes")
is comparing a literal against and array and therefor will not work. Since there is no defined string type in C you have to use pointers, but not directly, if you don't want to. In C strings are in fact arrays of char so you can declare them both ways eg:
char[3] decision ;
* char decision ;
Both will in point of fact work but you in the first instance the compiler will allocate the memory for you, but it will ONLY allocate 3 bytes. Now since strings in C are null terminated you need to actually allocate 4 bytes since you need room for "yes" and the null. Declaring it the second way simply declares a pointer to someplace in memory but you have no idea really where. You would then have to allocate memory to contain whatever you are going to put there since to do otherwise will more then likely cause a SEGFAULT.
To compare what you get from input you have two options, either use the strcomp() function or do it yourself by iterating through decision and comparing each individual byte against "Y" and "E" and "S" until you hit null aka \0.
There are variations on strcomp() to deal with uppercase and lowercase and they are part of the standard string.h library.