Comparing strings and keyboard inputs - c

When I enter "quit" on my keyboard, the if loop (marked by the comment "here quit is implemented") should return true and the program should end. But strcmp does not return zero. There are no compiler errors. I am not able to identify the problem.
int numInput(){
char str[10];
int num;
char nStr[10];
char q[4] = "quit"; //Quit
LAND:
scanf("%s",&str);
if (strcmp(q,str) == 0){ //Here quit is implemented
exit(0);
}else{
printf(str);
}
num = atoi(str);
itoa(num,nStr,10);
if (strcmp(nStr,str) != 0){
printf("Please enter numbers only!\nEnter number here:");
goto LAND;
}
return num;
}

The char array q doesn't have enough room to store the string "quit".
This string needs 5 characters: 4 for the letters and one for the terminating null byte. And because the array isn't big enough, attempting to use string functions on it causes these functions to read off the end of the array. This triggers undefined behavior.
The array needs to be at least one element larger:
char q[5] = "quit";
Or even better:
char q[] = "quit";
Which sizes the array to fit the initializer.
Also, this isn't correct:
scanf("%s",&str);
As you're passing a pointer to an array while the %s format specifier expects a char *. This should instead be:
scanf("%s",str);

Related

char pointers: invalid conversion from 'char*' to 'char'?

I cut out all the unnecessary code so no one gets too bored with my question... So I cant get the char array to work! on the last few lines of
*whatname = guyname;
*whatlastname = lastname;
I get an error saying invalid conversion from 'char*' to 'char'. Help would be much appreciated!
#include <stdio.h>
#include <ctype.h>
#include <string.h>
void getname(char *whatname, char *whatlastname);
int main()
{
int option = 0;
char guyname = 'x';
char lastname = 'x';
bool name_entered = false;
do{
printf("1. Enter name.\n");
printf("2. Enter exam scores.\n");
printf("3. Display average exam scores. \n");
printf("4. Display summary. \n");
printf("5. Quit. \n");
scanf("%i", &option);
if( option == 1 )
{
name_entered = true;
getname(&guyname, &lastname);
}
else if( option == 4 )
{
{
printf("%s %s based on your exam scores of \n",guyname, lastname);
}
else
{
printf("Please enter your name in option 1 and you exam scores in option 2 before continuing.\n");
}
}
else if( option == 5 )
{
printf(" Come back with a better grade next time.");
break;
}
}while (!(option >5 || option <1));
return 0;
}
void getname (char *whatname, char *whatlastname)
{
char guyname[32];
char lastname[32];
printf("Enter your first and last name : ");
scanf("%s %s", &guyname, &lastname);
guyname[0] = toupper( guyname[0] );
int len = strlen(guyname);
for(int i=1; i<len ; i++)
{
guyname[i] = tolower( guyname[i]);
}
lastname[0] = toupper( lastname[0] );
int len1 = strlen(lastname);
for(int k=1; k<len1; k++)
{
lastname[k]= tolower( lastname[k]);
}
printf("Your name is %s %s\n", guyname, lastname);
*whatname = guyname;
*whatlastname = lastname;
}
Dealing with char, char*, and char [] in C is a little confusing in the beginning.
Take a look at the following statements:
char str1[] = "abcd";
char const* str2 = "xyz";
char* cp = str1;
char c = *cp;
The first statement and the second statement are identical in their behavior. After the first statement is executed, str1 points to a location that contains 4 characters, in consecutive order. If you think of the memory locations for the string, you might see something like:
+---+---+---+---+
| a | b | c | d |
+---+---+---+---+
str1 points to the address where a is stored. There is a similar arrangement for storing the string "xyz" and str2 points to the address where x is stored.
In the third statement, you are creating cp and making it point where str1 is pointing. After that statement, both cp and str1 point to the same string - "abcd".
*cp evaluates to the character that exists at the address that cp points to. In this case, it will be 'a'.
In the fourth statement, you are initializing c with 'a', the character that exists at the address pointed to by cp.
Now, if you try a statement
*cp = str2;
it is a compiler error. *cp simply dereferences the address of cp. You can put a char at that location, not str2, which is a char*.
You can execute
*cp = *str2;
After that, the objects in the memory that str1 and cp point to will look like:
+---+---+---+---+
| x | b | c | d |
+---+---+---+---+
If you want to copy the string from the address pointed to by str1 to the address pointed to by cp, you can use the standard library function strcpy.
strcpy(cp, str2);
You have to be careful about using strcpy because you have to have enough valid memory to copy to. In this particular example, if you tried
char str3[2];
strcpy(str3, cp);
you will get undefined behavior since there isn't enough memory in str3 to be able to copy "abcd".
Hope that made sense.
Here's a modified version of your code that should work:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
void getname(char *whatname, char *whatlastname);
int main()
{
int option = 0;
char guyname[32];
char lastname[32];
bool name_entered = false;
do{
printf("1. Enter name.\n");
printf("2. Enter exam scores.\n");
printf("3. Display average exam scores. \n");
printf("4. Display summary. \n");
printf("5. Quit. \n");
scanf("%i", &option);
if( option == 1 )
{
name_entered = true;
getname(guyname, lastname);
}
else if( option == 5 )
{
printf(" Come back with a better grade next time.");
break;
}
}while (!(option >5 || option <1));
return 0;
}
void getname (char *whatname, char *whatlastname)
{
char guyname[32];
char lastname[32];
printf("Enter your first and last name : ");
scanf("%31s %31s", guyname, lastname);
guyname[0] = toupper( guyname[0] );
int len = strlen(guyname);
for(int i=1; i<len ; i++)
{
guyname[i] = tolower( guyname[i]);
}
lastname[0] = toupper( lastname[0] );
int len1 = strlen(lastname);
for(int k=1; k<len1; k++)
{
lastname[k]= tolower( lastname[k]);
}
printf("Your name is %s %s\n", guyname, lastname);
strcpy(whatname, guyname);
strcpy(whatlastname,lastname);
}
lot of things wrong here. You need to think about where the two string are going to be stored.
You are trying to return variable on the stack of getname - even if you fix the C code that wont work.
a) getname needs to be getname(char**, char**)
b) whatname and whatLastname need to be char *
c) call getname with (&whatname &whatLastName)
d) strdup the strings in getname into the two params (*whatname,...)
You have a pair of values in the main which are single characters.
You're passing in pointers to those characters, then dereferencing them (which gives you single characters again), then trying to assign character pointers to them. That definitely isn't going to work.
Even if you did,
whatname = guyname;
whatlastname = lastname;
which would be type-correct, it wouldn't do what you seem to want, which is to change the values in the calling function. It would only change the values of the argument variables in the subroutine.
If you're trying to return two strings found in the subroutine, change the calling code's variables to:
char *guyname = "x";
char *lastname = "x";
and change the function arguments to
void getname (char **whatname, char **whatlastname)
Then your assignment will be type-correct, and will change the pointers in the calling function.
There shouldn't be & in scanf of string.
first of all, using * on a pointer will dereference it (you did it on the last two lines)
secondly, you are sending to the function a pointer to a single char, not an array of chars so if you will write to its memory you will write on some other variable's memory.
What you should have done is declaring guysname and lastname as char arrays
char guysname[32];
and in your function just read your input directly into the parameters you recieve:
scanf("%s %s", whatname, whatlastname);
replace all instances of guysname and lastname for whatname and whatlastname. get rid of the last lines.
If you want to keep the char arrays inside the function anyway, just use
strcpy(whatname,guysname)
and the same for the last name.
You can't assign a char value to a char pointer, and you can't dereference an Lvalue.
whatname = &guyname;
whatlastname = &guylastname;
This is what you're looking for. However, it appears that you're just starting to play with pointers, and you may need to read up on them a little more before you start experimenting.

Character Pointers with Palindrome Checker in C

This is code I wrote that checks if a string is a palindrome or not. I need to revise this code so that it uses character pointers in it. Could someone give me some suggestions/tips...or show me how to do that? Thanks
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(){
char string1[20];
int i, length;
int flag = 0;
printf("Enter a string: ");
scanf("%s", string1);
length = strlen(string1);
for(i=0;i < length ;i++){
if(toupper(string1[i]) != toupper(string1[length-i-1])){
flag = 1;
break;
}
}
if (flag)
printf("%s is not a palindrome \n\n", string1);
else
printf("%s is a palindrome \n", string1);
return 0;
}
In your code you use string1[i] to access the current element from the beginning of the string, and string1[length-i-1] to access the current element from the end of the string. You could create two pointers, pb and pe, and then move them toward each other.
To define pointers, use this:
char *pb = &string1[0]; // Or just string1, compiler will convert it to pointer
char *pe = &string1[length-1];
To advance the pointers toward each other, use pb++ and pe--.
To see if the pointers have not crossed each other , check that pb < pe. Currently, your program checks the string twice; there's no need to do that - you can stop as soon as pe becomes less than or equal to the pb.
To access the character pointed to by the current pointer, use
toupper(*pb) != toupper(*pe)
You can combine the check with advancing the pointers, like this:
toupper(*pb++) != toupper(*pe--)
Note: it is not safe to use %s, because when users enter more characters than fits in your string1 buffer overrun results. You should specify the length of the buffer, like this:
scanf("%19s", string1); // Leave one char for null terminator
I'm not sure I completely understand the question, but I think this answers it. You actually are using character pointers. char string1[20] is the same as char *string1. The difference is that you've basically assigned the pointer to a block of memory. You could access the string in this way.
char string[20] = "foo";
printf("%c\n", string[0]); // will print 'f'
printf("%c\n", *string); // will also print 'f'
printf("%c\n", string[1]); // will print the first 'o'
printf("%c\n", *(string + 1)); // will also print the first 'o'
with char * it goes like this
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main()
{
char string1[20];
int i, length;
int flag = 0;
printf("Enter a string: ");
scanf("%s", string1);
length = strlen(string1);
char *start=string1;
char *end=&string1[length-1];
//only check upto half
for(i=0;i <= (length-1)/2 ;i++)
{
if(toupper(*(start+i)) != toupper(*(end-i)))
{
flag = 1;
break;
}
}
if (flag)
printf("%s is not a palindrome \n\n", string1);
else
printf("%s is a palindrome \n", string1);
return 0;
}
cant we just copy the original string to another array, and then use strrev() to reverse the copied string and then finally compare the original string with the reversed string?
Like this
1.get new string
2.copy string to new array
3.reverse the copied string using strrev
4.use strcmp to check if both are same or not?
this seemed easier
(i am a beginner so please correct me if i am wrong)

Passing pointers to string arrays to toupper() in C

I'm trying to pass a pointer array of strings to function toupper() in C.
main() {
char *choice[1];
scanf("%s", choice);
printf("%s", toupper(&choice[0]));
}
I always type in a lowercase word such as "modify" to test it. Different variations of this, such as toupper(*choice[0]) or toupper(*choice) or mixtures of them all, including &, have either thrown an error or returned the same lowercase "modify". Any suggestions?
To start with array of char pointers having one element doesn't make much sense to me since it will only point to one string.Why not declare a char array if you just want a single string?
Prototype of toupper is this:
int toupper( int ch );
It doesn't take an array.
You can try like this :
#include <stdio.h>
#include <ctype.h>
int main()
{
char str[25];
int i = 0;
setbuf(stdout,NULL);
printf ("enter the name \n");
fgets (str,sizeof str-1, stdin);
printf ("the name entered in upper case is :\n");
while (str[i])
{
int c = str[i];
printf ("%c",toupper(c));
i++;
}
return 0;
}
NOTE- Do not use scanf for taking strings try fgets , its better.
Before you call scanf, you need to allocate some space for the characters to be stored in. You only allocate a single pointer and then you don't even set it to point to anything. Similarly, toupper returns the converted character, which is not a string, so passing it to printf through %s is also wrong.
Something like this should serve the purpose.
#include<stdio.h>
#include<ctype.h>
void StrToUpper(char *str)
{
while(*str != '\0')
{
*str = toupper(*str);
str++;
}
}
int main()
{
char *choice[1];
choice[1] = new char[10];
scanf("%s", choice[1]);
StrToUpper(choice[1]);
printf("%s", choice[1]);
return 0;
}
In the program, you have array of pointers.
So:
Allocate memory for your string
call toupper(choice[0][0]);
toupper takes only a character value (between 0 and 255), not a pointer or array.

use get function to read from 2 arrays of char and store in variable input1 and input2. then join both variables and display the result in c.

I am supposed to create two arrays of char called input1 and input2 that can hold 1000 characters each and one array of char called input that can hold 2000 characters. Use the gets function to read in two different sentences from the user and store it in the variable input1 and input2. Join input1 and input2 and place the result in the input variable.
here is my code
main() {
char input;
get(input1);
get(input2);
input = input1 + input2;
}
char a(string result){
char input1[1000][1000];
printf("please enter the something\n");
scanf("%s", input1);
return input1;
}
char b(string result){
char input2[1000][1000];
printf("please enter the something\n");
scanf("%s", input2);
return input2;
}
#include <stdio.h>
#include <string.h>
int main(){
char input1[1000] = {0};
char input2[1000] = {0};
printf("please enter the something\n");
scanf("%999[^\n]%*c", input1);
printf("please enter the something\n");
scanf("%999[^\n]%*c", input2);
char input[2000];
sprintf(input, "%s %s", input1, input2);
printf("%s\n", input);
return 0;
}
To start with, in C there is no type called string.
To continue, with the declaration
char input1[1000][1000];
you declare input1 to be an array of arrays, or an array of 1000 strings where each string is 999 characters long.
You are also trying to return this array of strings from functions returning only a single character. Even if you change the functions to have only a single string, and you return a pointer to this string, you will still have problems (you can't return pointers to local variables).
Then you can't use the + operator to concatenate strings.
All in all, you need to start over with a good tutorial, and get a better grasp of the language first.

Running isdigit() on a scanfed Character in C

I am refreshing my C skills and am having a little bit of difficulty with a simple program I am working on. Here it is:
#include <stdio.h>
#include <ctype.h> // for isdigit()
#include <stdlib.h> // for atoi()
int main (int argc, const char * argv[])
{
// first read in # of file events to follow, if not an int,
// complain & abort
char *input;
input = malloc(2); // input[0] holds the character
// input[1] holds the terminator
int numLines = 0;
scanf("%c", &input);
if (isdigit((int)input)) {
numLines = atoi(input);
} else {
printf("First line of input must be int type! Aborting...\n");
return 1;
}
//...
}
The problem is, then even when I enter a number (i.e. 2) it still outputs the aborting message and exits:
2
First line of input must be int type! Aborting...
I am having a hard time figuring out why it behaves like it is and what I should do to fix the problem. Shouldn't the '%c' specifier tell the compiler to take in the input as an ANSI character and then isdigit() should properly interpret that to be an integer?
Thanks in advance!
Change this:
scanf("%c", &input);
if (isdigit((int)input)) {
to this:
scanf("%c", input);
if (isdigit(input[0])) {
As it is right now, you are overwriting the pointer itself, rather writing to the allocated memory.
Also, you need to null-terminate:
input[1] = '\0';
Furthermore, it's not necessary to allocate memory for this. You can get away with just:
char input[] = " ";
scanf("%c", input);
if (isdigit(input[0])) {
numLines = atoi(input);
or alternatively:
char input;
scanf("%c", &input);
if (isdigit(input)) {
numLines = input - '0';
Change your code to:
char input[2] = {0}; // <<-- you don't clear the memory after malloc,
// your atoi might fail. No need for malloc here.
int numLines = 0;
scanf("%c", &input[0]);
if (isdigit((int)input[0])) {
numLines = atoi(input);
} else {
printf("First line of input must be int type! Aborting...\n");
return 1;
}
And you're good. No need to dynamically allocate here, its just a waste of effort.
When you pass &input to scanf, you are passing a pointer to a char *. You should just pass the pointer itself, that is,
scanf("%c", input);

Resources