Cannot Break Out of a "While" loop - c

I am converting a 2-d char array into a 2-d int array, and I need to break out of the while loop if \0 or \n comes in the string. This code gives segmentation fault.
Definition of Array is and the indices are less than 1000 and the 2-d char array tempCharArray is already stored. What is the problem with my code?
//Array[tempCount][1000];
for(int i=0;i<tempCount;i++)
{
strtok(tempCharArray[i]," ");
while(tempCharArray[i]!="\0" || tempCharArray[i]!="\n")
{
Array[i][arrayindex]=atoi(strtok(NULL," ");
arrayindex++;
}
arrayindex=0;
}

You are a little mixed up (a) between char literals and string literals and (b) with your while loop logic.
Change this line:
while(tempCharArray[i]!="\0" || tempCharArray[i]!="\n")
to:
while(tempCharArray[i]!='\0' && tempCharArray[i]!='\n')
Note that your compiler should have warned you about mistake (a) - you do have warnings enabled, I hope ?
Edit: it seems from subsequent comments that tempCharArray may actually be an array of strings ? In that case you would need to do this to fix problem (a):
while(strcmp(tempCharArray[i],"")!=0 && strcmp(tempCharArray[i],"\n")!=0)
Note that you can not compare strings with == or != - you need to use strcmp.
The logic bug and its fix still apply of course.

If tempCharArray is the char array, you are trying to compare a single character with a complete string. That will not do what you want it to. Instead compare it to a character literal:
while(tempCharArray[i]!='\0' || tempCharArray[i]!='\n')
Note the use of single quotes instead of double.

You need to use && instead of || because the loop continues as long as the condition is true (and this is—in your case—as long as tempCharArray[i] is '\0' and '\n'
You need to use single quotes, because you compare character literals
This leads to
while (tempCharArray[i] != '\0' && tempCharArray[i] != '\n')

Related

In C, how can I know if a string char has a specific value?

For example,
Supposing that I've created a string called string[100] and assigned some values to it, how can I know if the value of string[n] is "m"?
I've thought about creating another char variable and assigning "m" to it and then comparing string[n] to char with strcmp, but it seems kinda like a waste of code creating a variables just for that since on the program I'm trying to code I'll have to compare string[n] with a lot of stuff.
Thanks in advance and sorry for my poor knowledge on C, i'm starting to learn it today.
You're just beginning, and strings in C are not as "user-friendly" as they are in some other programming languages, so there's nothing wrong with asking.
In C a string is just an array of characters, with a trailing null character ('\0') to indicate the end of the string. Each character in that array, though, as mentioned in the comments, is just a character, which is a small integer that can be compared with simple operators like ==, !=, >, <, etc.
If we want to know if a string begins with an 'm' for instance, we can write a simple function that checks the first element of the array. Please note that C arrays are indexed starting at 0.
int starts_with(char ch, char *str) {
return s[0] == ch;
}
Once you learn how to use loops and other control flow mechanisms in C, you'll be able to do more complex operations on strings. As an example, determining if a character occurs in a string.
int contains_char(char ch, char *str) {
for (char *c = str; *c; c++) {
if (c == ch) {
return 1;
}
}
return 0;
}

My C program isn't recognizing valid input, think it's because of a newline issue

I have a C program that is supposed to evaluate whether the user entered a H or a M. I have some input validation to ensure that the user enters either H or M. However, when those are entered, the procedure treats it like the user entered something else. I have a feeling that this is because scanf is adding a newline character to the input which causes it to fail the comparison. I'm trying to find ways to strip out this newline character, but I've had no luck. I've tried putting getchar() after the scanf, but that didn't work. I've tried using fgets and that didn't work either. I tried changing the format indicator from %s to %c and that didn't work.
Here is the entire procedure:
char GetEmployeeStatus()
{
// declare variable
char strEmployeeStatus = "";
int intEmployeeStatusResult = 1; // assume valid input
do
{
// get user input
printf("Please enter the employee's status: H for hourly or M for management. \n");
intEmployeeStatusResult = scanf("%s", &strEmployeeStatus);
} while (intEmployeeStatusResult == 0 || strEmployeeStatus != "H" || strEmployeeStatus != "M");
return strEmployeeStatus;
}
Thank you for any help, I really appreciate it.
Add the correct headers. Then enable compiler warnings and compile it again.
Mainly, you're mixing up string literals ("foobar") with character literals ('x'); this is what GCC has to say about the initialization:
blah.c: In function ‘GetEmployeeStatus’:
blah.c:6:30: warning: initialization makes integer from pointer without a cast [-Wint-conversion]
char strEmployeeStatus = "";
^~
With similar warnings from the comparisons.
Also consider what the %s conversion for scanf() does. From the Linux man page:
s
Matches a sequence of non-white-space characters; the next pointer must be a pointer to the initial element of a character array that is long enough to hold the input
sequence and the terminating null byte ('\0'), which is added automatically. The input string stops at white space or at the maximum field width, whichever occurs
first.
Here, in your code, strEmployeeStatus is just one char. You are giving scanf() a pointer-to-char correctly, though, so the compiler has a hard time warning about that.
char strEmployeeStatus;
scanf("%s", &strEmployeeStatus);
Then, the loop condition: strEmployeeStatus != "H" || strEmployeeStatus != "M". That's (X is not A OR X is not B). What happens in an expression like this when X is A, B, or C? What are the values of the subexpressions, and what's then the value of the whole OR expression in each case?
I talked with someone IRL, and we fixed the problem. The issue wasn't with scanf at all. The problem was my compound OR statement. The line below:
intEmployeeStatusResult == 0 || strEmployeeStatus != "H" || strEmployeeStatus != "M"
will always evaluate to true even if H or M is entered. I changed the line to:
intEmployeeStatusResult == 0 || strEmployeeStatus != "H" && strEmployeeStatus != "M"
and the program works as intended now.

Using sscanf to validate a string input

I have just started learning C after coding for some while in Java and Python.
I was wondering how I could "validate" a string input (if it stands in a certain criteria) and I stumbled upon the sscanf() function.
I had the impression that it acts kind of similarly to regular expressions, however I didn't quite manage to tell how I can create rather complex queries with it.
For example, lets say I have the following string:
char str[]={"Santa-monica 123"}
I want to use sscanf() to check if the string has only letters, numbers and dashes in it.
Could someone please elaborate?
The fact that sscanf allows something that looks a bit like a character class by no means implies that it is anything at all like a regular expression library. In fact, Posix doesn't even require the scanf functions to accept character ranges inside character classes, although I suspect that it will work fine on any implementation you will run into.
But the scanning problem you have does not require regular expressions, either. All you need is a repeated character class match, and sscanf can certainly do that:
#include <stdbool.h>
bool check_string(const char* s) {
int n = 0;
sscanf(s, "%*[-a-zA-Z0-9]%n", &n);
return s[n] == 0;
}
The idea behind that scanf format is that the first conversion will match and discard the longest initial sequence consisting of valid characters. (It might fail if the first character is invalid. Thanks to #chux for pointing that out.) If it succeeds, it will then set n to the current scan point, which is the offset of the next character. If the next character is a NUL, then all the characters were good. (This version returns OK for the empty string, since it contains no illegal characters. If you want the empty string to fail, change the return condition to return n && s[n] == 0;)
You could also do this with the standard regex library (or any more sophisticated library, if you prefer, but the Posix library is usually available without additional work). This requires a little bit more code in order to compile the regular expression. For efficiency, the following attempts to compile the regex only once, but for simplicity I left out the synchronization to avoid data races during initialization, so don't use this in a multithreaded application.
#include <regex.h>
#include <stdbool.h>
bool check_string(const char* s) {
static regex_t* re_ptr = NULL;
static regex_t re;
if (!re_ptr) regcomp((re_ptr = &re), "^[[:alnum:]-]*$", REG_EXTENDED);
return regexec(re_ptr, s, 0, NULL, 0) == 0;
}
I want to use sscanf() to check if the string has only letters, numbers and dashes in it.
Variation of #rici good answer.
Create a scanset for letters, numbers and dashes.
//v The * indicates to scan, but not save the result.
// v Dash (or minus sign), best to list first.
"%*[-0-9A-Za-z]"
// ^^^^^^ Letters a-z, both cases
// ^^^ Digits
Use "%n" to detect how far the scan went.
Now we can use determine if
Scanning stop due to a null character (the whole string is valid)
Scanning stop due to an invalid character
int n = 0;
sscanf(str, "%*[-0-9A-Za-z]%n", &n);
bool success = (str[n] == '\0');
sscanf does not have this functionality, the argument you are referring to is a format specifier and not used for validation. see here: https://www.tutorialspoint.com/c_standard_library/c_function_sscanf.htm
as also mentioned sscanf is for a different job. for more in formation see this link. You can loop over string using isalpha and isdigit to check if chars in string are digits and alphabetic characters or no.
char str[]={"Santa-monica 123"}
for (int i = 0; str[i] != '\0'; i++)
{
if ((!isalpha(str[i])) && (!isdigit(str[i])) && (str[i] != '-'))
printf("wrong character %c", str[i]);//this will be printed for spaces too
}
I want to ... check if the string has only letters, numbers and dashes in it.
In C that's traditionally done with isalnum(3) and friends.
bool valid( const char str[] ) {
for( const char *p = str; p < str + strlen(str); p++ ) {
if( ! (isalnum(*p) || *p == '-') )
return false;
}
return true;
}
You can also use your friendly neighborhood regex(3), but you'll find that requires a surprising amount of code for a simple scan.
After retrieving value on sscanf(), you may use regular expression to validate the value.
Please see Regular Expression ic C

Compare character by character 2 strings

I am trying to code a program that tells me if 2 strings are identcal. If they have one different chracter they are not.
I have this code, but it does not work, why?
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main() {
char str1[30], str2[30];
int i;
printf("\nEnter two strings :");
gets(str1);
gets(str2);
for (i=0;str1[i]==str2[i];i++)
if (str1[i]!=str2[i]){
printf("They are not identical");
}
else continue;
return (0);
}
It compiles with 0 errors and 0 warnings, but when I introduce 2 not identical strings it returns nothing. (The same happens when I introduce 2 identical strings, but that is how is supposed to be)
What should I do to fix it?
There is one important thing wrong here. First of all: The classic "c style string" is null terminated. Allthough there are other alternatives (like storing the length outside of the string), the null terminated string is part of the language (as string literals in code are null terminated by the compiler), and the runtime library (most string functions handle the \0 at the end of the string).
gets also appends a \0 at the end of the entered string:
http://www.cplusplus.com/reference/cstdio/gets/
You are comparing not only the entered strings, but also anything (random) after that string in memory.
It should look like this:
for(int i=0;str1[i]==str2[i];i++){
if(str1[i]==0) {
printf("equal");
}
}
printf("not equal");
There are other alternative, like using pointer. But on modern compilers they should produce roughly the same machine code.
Please note that there are C runtime library functions to compare strings:
strcmp is the most basic one, just two char *:
strncmp allows to specify the maximium chars to compare, do compare a part of a string:
There are other, just check out the links.
Please note that it's better to use the library functions, because even if in such a "simple" function. There are optimized ways to compare string. Like comparing in native word sizes. On 32 bit platforms you spend four time more time in comparation, not including the masking needed to perform byte wise operations.
Your for loop is:
for (i=0;str1[i]==str2[i];i++)
if (str1[i]!=str2[i]){
printf("They are not identical");
}
else continue;
Let's say str1 is "abc" and str2 is "xyz".
The conditional in the for loop will evaluate to false for i = 0. Hence, you will never get to the statement:
if (str1[i]!=str2[i]){
Consequently, you will never execute:
printf("They are not identical");
You can fix the logic error by using:
for (i=0; str1[i] != '\0' && str2[i] != '\0'; i++)
{
if (str1[i]!=str2[i]) {
break;
}
}
// If at end of the loop, we have reached the ends
// of both strings, then they are identical. If we
// haven't reached the end of at least one string,
// then they are not identical.
if ( str1[i] != '\0' || str2[i] != '\0' )
{
printf("They are not identical");
}
I have this code, but it does not work, why?
Because your looping condition str1[i]==str2[i] will make the inner if condition be always false.
What should I do to fix it?
Simple code:
for ( i=0; str1[i]==str2[i] && str1[i]!='\0'; i++) {
}
if ( str1[i]!=str2[i] ) {
printf("They are not identical");
}
or
i=0;
while ( str1[i]==str2[i] && str1[i]!='\0' ) {
i++;
}
if ( str1[i]!=str2[i] ) {
printf("They are not identical");
}
Let's say you have two string in which the first character is different. then you will not enter the loop as the condition of the loop (str1[i]==str2[i]) fails, therefore the condition should be ( str1[i]!='\0' && str2[i]!='\0' ). The '\0' is the last character of the c-style string.
You can also use string built in functions like " strcmp(str1,str2) ".

Why doesn't t != "Q" kill while loop when gets(t) gets input "Q" from command line?

I'm declaring t[1] = "a" and have gets(t) in while loop, checking for condition t != "Q" every time it loops.
#include <stdio.h>
int main(void)
{
char t[1] = "a";
printf("Enter a character or 'Q' to quit.");
while (t != "Q")
{
gets(t);
printf("%s\n", t);
}
return(0);
}
The program just keeps looping even when I input Q and press enter.
There are several things wrong with your program.
char t[1] = "a";
A string consists of a sequence of characters terminated by a null character '\0'. You haven't left enough room in t to hold the character 'a' plus the terminating '\0'. Due to a special rule, this stores just the character 'a' in t[0]; this t doesn't contain a string.
while (t != "Q")
Here's the most direct cause of the problem you're seeing. C doesn't support equality comparisons for strings, or for arrays. An array expression usually "decays" to a pointer to its first element. This compares the address of the first element of t to the address of the first element of the string literal "Q". Obviously they'll never be equal.
gets(t);
Never use the gets function. It is inherently unsafe; it doesn't let you specify how long the target array is, so you can't avoid writing past the end of the array. Since t is only one element long, this will overflow (unless you type an empty line).
For what you're doing, you probably want to read a single character at a time, probably using getchar(). Remember that getchar() returns an int, not char; it returns EOF to indicate end-of-file. And if you type, for example, Q followed by Enter, two calls to getchar() will return 'Q' and '\n'.
t stands for address of your array. So you are comparing address to string. Use t[0] != 'Q' or strcmp(t, "Q") != 0.

Resources