I'm brand new to programming..im just trying to make my own program to find the volume and surface area of spheres and cylinders. I cant figure out why this program keeps crashing before it will get to the rest of the code. I'm guessing the char* might be wrong but i cant see why it would be.
int main()
{
char* solid;
char* unit;
printf("Welcome to the Center of Spheres and Cylinders!\n");
printf("Would you like to look at a Sphere or a Cylinder?: ");
scanf("%s", solid);
if(solid == "Cylinder" || solid == "cylinder")
{
printf("You chose to look at a Cylinder.\n");
else if(solid == "Sphere" || solid == "sphere")
{
printf("You chose to look at a Sphere.\n");
it crashes just after I input for scanf...when i type in either cylinder or sphere it crashes. Thank you for the help
solid is a character pointer, it is not pointing to any allocated memory location which is causing your program crash when you try to read data into it with scanf() ( and which is why it crashes right after that call as you observe).
After you declare
char *solid;
you should malloc() a certain amount of storage for it to point to. Alternatively you could have declared an array named solid
char solid[100];
Note that the crash is actually a good thing in that it is helpful to show there's a problem with an errand pointer. This may not always happen unfortunately depending on where a pointer in memory is pointing too.
The problem is with the line
if(solid == "Cylinder" || solid == "cylinder")
U cannot compare strings like that in C. Instead use strcmp library function available in C.
The code should be something like below
if( (strcmp(solid,"Cylinder")==0) || (strcmp(solid,"cylinder")==0) )
Hope this helps.
char* solid; creates a character pointer that points to an arbitrary location (at least for automatic variables, which is what you have in your code). Then, when you try to sccanf into that location, you're invoking undefined behaviour because there is no valid backing storage.
Something like char solid[100]; would create the backing storage, solving that immediate problem, since it allocates space for the characters to be stored. However, there are at least two other problems with your code.
The first is that you don't compare strings in C with ==, that merely compares the pointers, not the content behind the pointers. To compare the content, C provides a strcmp function so, rather than:
if (solid == "something")
you should have:
if (strcmp (solid, "something") == 0)
Some implementations may also provide stricmp which ignores case so you don't have to do:
if ((strcmp (solid, "something") == 0) || (strcmp (solid, "Something") == 0))
instead going with:
if (stricmp (solid, "something") == 0)
which will allow any characters to be upper or lowercase, such as SomeThing.
However, that's not standard C so it may not be available everywhere.
Your other major problem lies with scanf("%s"). Using an unbounded string here is unsafe as you're subject to buffer overflows if the user enters more than you expect. For example, if you use the afore-mentioned char solid[100] and the user enters five hundred characters, it's likely to trash your stack and cause yet another crash.
If you want a truly robust user input function, have a look at this one. It has overflow protection and throws away the rest of the line if necessary so that subsequent inputs are not affected.
Your program has several "flaws", as pointed out by the others:
The "star" denotes a pointer. A pointer must point to a location in memory, which can be done via malloc(), pointer assignment/manipulation, or explicit bit addresses. For more information on pointers, you can read this: http://pw1.netcom.com/~tjensen/ptr/pointers.htm (But seriously, pointers? You've mentioned you're a beginner in programming; pointers are an advanced concept not only in C, but in computer science as well. Anyways, do not think too much about them at the moment.)
String comparison in C is not done by the simple equality operator, but via bit comparison (which is automagically done by the library). The equality operator (==) compares only primitive types (int, char, etc) but not user-defined types or arrays (a string is a character array). You have to use strcmp() (or strncmp() to compare the first n bytes from an optional offset). You can search Google for the documentation of strcmp() and strncmp() for more information.
Keeping these concepts in mind, your program will be like this:
#include <string.h> /**Contains string manipulation functions; very important **/
#include <ctype.h> /**Contains tolower() **/
int main()
{
char* solid;
char* unit;
printf("Welcome to the Center of Spheres and Cylinders!\n");
printf("Would you like to look at a Sphere or a Cylinder?: ");
scanf("%s", solid);
if(strcmp(tolower(solid), 'cylinder') == 0)
{
printf("You chose to look at a Cylinder.\n");
else if(strcmp(tolower(solid), 'sphere') == 0)
{
printf("You chose to look at a Sphere.\n");
}
/** Other code here **/
return 0;
}
As you might have guessed, tolower() turns a string to lowercase. And additional FYI, an array is a pointer, so the justification in using the "star" notation for storing your input from scanf.
Related
It may be really simple, but I don't really know what to do now.
I just recently got in programming and I thought I should start by learning C, I know a few stuff here and there but I just recently got into this problem and I can't figure it out.
Im trying to make a register/login system that stores the credentials into strings using scanf(), I don't really know how to get the login part to work. Do I need to create more strings and store the input there? Or how can I compare the user's input to the value in the strings?
My code is currently looking like this:
#include<stdlib.h>
#include<time.h>
char user[30] = "";
char password[30] = "";
char yn[30] = "";
char Y[1] = "Y";
char N[1] = "N";
int main() {
printf("Register\n");
printf("The User or Password can't be longer than 30 characters\n");
printf("User: \n");
scanf("%s", &user);
if (user == NULL)
printf("User can't be empty\n");
else
printf("Password: \n");
scanf(" %s", &password);
if (password == NULL)
printf("Password can't be empty\n");
printf("User saved as: \n");
printf("%s\n", &user);
printf("Password saved as: \n");
printf("%s\n", &password);
printf("Is this correct?\n");
printf("Y/N\n");
scanf("%s", yn);
if(yn == Y){
printf("\e[1;1H\e[2J");
}
if(yn == N){
printf("Restarting...");
}
printf("Login\n");
printf("User: \n");
}
It all works well (except I can't figure out how to clear the console before asking to log in, this wont work printf("\e[1;1H\e[2J");), I even managed to print out the user's input to the console for him to make sure its correct and I made a (Y/N) thingy. Can someone help me please?
You can create functions instead of having them all in the main.
Create a register function that saves the data and a login function that asks for data as parameters and the call it in the main.
Maybe you can create a simple menu.
When you first learn a language, you discover certain patterns of how it can be used. Some of your problems come from overusing patterns where they don't make sense.
For example, you know you can compare two variables with == but that compares values, and in some cases you are comparing references as if they were values. References are memory addresses, and if you have two letters Y in RAM then they are distinct, having two different references, even if their value is the same.
Since a lot of your processing uses strings, read through the functions available when you #include <string.h> You will hear a lot about how some of these are unsafe to use; for now I recommend skipping safety arguments as they make more sense after you know how to call the functions.
For example
if (yn == Y) {
is not going to give you the desired result, but
if ( strcmp( toupper( yn[0] ), "Y" ) == 0 ) {
will give you the desired result. As in most cases, there are other ways to write the same logic; but, for those who want to offer more efficient ways of checking yn, this is an example designed to show off string functions.
Strings in C are not single values. They are an address (sometimes called a reference) to a pieced of memory, which if you keep reading char-by-char should eventually end in a NULL character, a char containing the number 0. This means that they cannot be compared directly as in yn == Y because you are comparing two memory addresses, not two sequences of chars.
The above example is a simplification of what strings can be. It's a good enough of a definition for a beginner; but, over time you will find that this definition is very old, and has been revised over time. The problem is that a char can only hold 8 bits, so when more than 256 distinct values were needed, a solution was created to hold more values.
The first solution was to use a "wide character" called a wchar, which has the type of wchar_t. This is like a char, but it holds 16 bits. This started the whole "char" vs "wchar_t" problems. For now you can ignore them, but be aware that if you ever work with wchar_t you need wchar compatible functions.
The second solution was to introduced Unicode, which provides enough characters that nearly every language can be written within Unicode, even most dead languages, emojis, upside down text, etc. Unicode doesn't have a single way of representing its characters, but there are two popular ones for the beginning programmer. UTF-32, which used 32 bytes for each character, is popular because it is easy to program. UTF-8 is popular because it is the effective "correct choice" for the Internet due to it extending ASCII and being the format of the Internet.
Once you get familiar with strings, you might want to spend some quality time with UTF-8.
Good luck.
I am absolutely new to C programming. Currently I am preparing for my new course of studies IT Security. In a slightly older exam I found a task where I have no approach how to solve it. The task is in German. In principle it is about finding critical errors.
It is not written how the passed parameters look like.
1) I have come to the point that you should not use strcpy because it has no bounds checking.
2) Also char[10] should not be used if you want to store 10 characters (\0). It should be char[11].
Is it possible to read Adresses or write sth due the printf(argv[1]) command ?
I would like to mention again that you help me here personally and do not help to collect bonus points in the university.
#include <stdio.h>
int main(int argc, char *argv[])
{
char code[10];
if(argc != 2) return 1;
printf(argv[1]);
strcpy(code, "9999999999");
for(int i = 0; i < 10; ++i){
code[i] -= argv[1][i] % 10;
}
printf(", %s\n", code);
return 0;
}
See
related.
you should not use strcpy() because it has no bounds checking
Nothing in C has bounds checking unless either
the compiler writer put it there, or
you put it there.
Few compiler writers incorporate bounds checking into their products, because it usually causes the resulting code to be bigger and slower. Some tools exist (e.g.
Valgrind,
Electric Fence)
to provide bounds-checking-related debugging assistance, but they are not commonly incorporated into delivered software because of limitations they impose.
You absolutely should use strcpy() if
you know your source is a NUL-terminated array of characters, a.k.a. "a string", and
you know your destination is large enough to hold all of the source array including the terminating NUL
because the compiler writer is permitted to use behind-the-scenes tricks unavailable to compiler users to ensure strcpy() has the best possible performance while still providing the behaviour guaranteed by the standard.
char[10] should not be used if you want to store 10 characters (\0)
Correct.
To store 10 characters and the terminating NUL ('\0'), you must have at least 11 characters of space available.
Is it possible to read Adresses or write sth due the printf(argv[1]) command ?
In principle: maybe.
The first argument to printf() is a format string which is interpreted by printf() to determine what further arguments have been provided. If the format string contains any format specifications (e.g. "%d" or "%n") then printf() will try to retrieve corresponding arguments.
If they were not in fact passed to it, then it invokes Undefined Behaviour which is Bad.
An attacker could run your program giving it a command-line argument containing format specifiers, which would lead to such UB.
The right way to print an arbitrary string like this with printf() is printf("%s", argv[1]);
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
I am originally a Java programmer who is now struggling with C and specifically C's pointers.
The idea on my mind is to receive a string, from the user, on a command line, into a character pointer. I then want to access its individual elements. The idea is later to devise a function that will reverse the elements' order. (I want to work with anagrams in texts.)
My code is
#include <stdio.h>
char *string;
int main(void)
{
printf("Enter a string: ");
scanf("%s\n",string);
putchar(*string);
int i;
for (i=0; i<3;i++)
{
string--;
}
putchar(*string);
}
(Sorry, Code marking doesn't work).
What I am trying to do is to have a first shot at accessing individual elements. If the string is "Santillana" and the pointer is set at the very beginning (after scanf()), the content *string ought to be an S. If unbeknownst to me the pointer should happen to be set at the '\0' after scanf(), backing up a few steps (string-- repeated) ought to produce something in the way of a character with *string. Both these putchar()'s, though, produce a Segmentation fault.
I am doing something fundamentally wrong and something fundamental has escaped me. I would be eternally grateful for any advice about my shortcomings, most of all of any tips of books/resources where these particular problems are illuminated. Two thick C books and the reference manual have proved useless as far as this.
You haven't allocated space for the string. You'll need something like:
char string[1024];
You also should not be decrementing the variable string. If it is an array, you can't do that.
You could simply do:
putchar(string[i]);
Or you can use a pointer (to the proposed array):
char *str = string;
for (i = 0; i < 3; i++)
str++;
putchar(*str);
But you could shorten that loop to:
str += 3;
or simply write:
putchar(*(str+3));
Etc.
You should check that scanf() is successful. You should limit the size of the input string to avoid buffer (stack) overflows:
if (scanf("%1023s", string) != 1)
...something went wrong — probably EOF without any data...
Note that %s skips leading white space, and then reads characters up to the next white space (a simple definition of 'word'). Adding the newline to the format string makes little difference. You could consider "%1023[^\n]\n" instead; that looks for up to 1023 non-newlines followed by a newline.
You should start off avoiding global variables. Sometimes, they're necessary, but not in this example.
On a side note, using scanf(3) is bad practice. You may want to look into fgets(3) or similar functions that avoid common pitfalls that are associated with scanf(3).
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.