Check for particular characters in array in C - c

I would like to check for certain characters in an array at certain positions.
The array starts with $$$$ then has eight characters then another $, eight more characters and finishes with $$$$. For example char my_array[50] = "$$$$01FF4C68$02543EFE$$$$";
I want to check that all the positions where there are supposed to be $ do have them.
I could split the array into the three parts that contain the characters and then test for them separately but is there a better way of doing this?

Why complicate things?
if (my_array[0] != '$'
|| my_array[1] != '$'
|| my_array[2] != '$'
|| my_array[3] != '$'
|| my_array[12] != '$'
|| my_array[21] != '$'
|| my_array[22] != '$'
|| my_array[23] != '$'
|| my_array[24] != '$')
{
printf("Wrong!\n");
}

Use strstr()
To check if the array begins with eight $ : strstr(my_array, "$$$$$$$$")
To check if the array ends with eight $ : strstr(my_array + 16, "$$$$$$$$")
The +16 is here to shift the pointer so the beginning of my_array + 16 will be the place were the $ are supposed to be.

You might want to use the strstr functinn to find the $$$....

yes there is, you might want to use Regular Expressions, Please read http://www.peope.net/old/regex.html

If you use POSIX-compatible platform and some more complex patterns are about to emerge in your code, you can take a look at regular expressions, e.g. PCRE

You could also avoid using strstr since the format is simple and fixed; until the example format holds::
bool ok = strlen(my_array) >= 25 /* just be sure there are at least all expected chars */ &&
strncmp(my_array, "$$$$", 4) == 0 &&
strncmp(my_array + 12, "$", 1) == 0 /* my_array[12] == '$' */&&
strncmp(my_array + 21, "$$$$", 4) == 0;

A long option without using the string.h library is, make 3 tests:
#include <stdio.h>
int firstTest( char a[] );
int secondTest( char a[] );
int thirdTest( char a[] );
int main (void)
{
int result;
char my_array[50] = "$$$$01FF4C68$02543EFE$$$$";
if( ( firstTest( my_array ) == 1 ) && ( secondTest( my_array ) == 1 ) && ( thirdTest( my_array ) == 1 ) ){
printf( "The string is valid.\n" );
result = 1;
}
else{
printf( "The string is invalid.\n" );
result = 0;
}
return 0;
}
int firstTest( char a[] )
{
int i;
for( i = 0; i < 4; i++ ){
if ( a[i] != '$' ){
return 0;
break;
}
return 1;
}
}
int secondTest( char a[] )
{
if( my_array[12] != '$' )
return 0;
else
return 1;
}
int thirdTest( char a[] )
{
int i;
for( i = 21; i < 25; i++ ){
if ( a[i] != '$' ){
return 0;
break;
}
return 1;
}
}

sscanf should do the work
char my_array[50] = "$$$$01FF4C68$02543EFE$$$$";
int n,m;
if( !sscanf(my_array,"$$$$%*8[0-9A-H]%n$%*8[0-9A-H]$$$$%n",&n,&m) && n==12 && m==25 )
puts("ok");
else
puts("not ok");

Related

Checking whether a string consists of two repetitions

I am writing a function that returns 1 if a string consists of two repetitions, 0 otherwise.
Example: If the string is "hellohello", the function will return 1 because the string consists of the same two words "hello" and "hello".
The first test I did was to use a nested for loop but after a bit of reasoning I thought that the idea is wrong and is not the right way to solve, here is the last function I wrote.
It is not correct, even if the string consists of two repetitions, it returns 0.
Also, I know this problem could be handled differently with a while loop following another algorithm, but I was wondering if it could be done with the for as well.
My idea would be to divide the string in half and check it character by character.
This is the last function I tried:
int doubleString(char *s){
int true=1;
char strNew[50];
for(int i=0;i<strlen(s)/2;i++){
strNew[i]=s[i];
}
for(int j=strlen(s)/2;j<strlen(s);j++){
if(!(strNew[j]==s[j])){
true=0;
}
}
return true;
}
The problem in your function is with the comparison in the second loop: you are using the j variable as an index for both the second half of the given string and for the index in the copied first half of that string. However, for that copied string, you need the indexes to start from zero – so you need to subtract the s_length/2 value from j when accessing its individual characters.
Also, it is better to use the size_t type when looping through strings and comparing to the results of functions like strlen (which return that type). You can also improve your code by saving the strlen(s)/2 value, so it isn't computed on each loop. You can also dispense with your local true variable, returning 0 as soon as you find a mismatch, or 1 if the second loop completes without finding such a mismatch:
int doubleString(char* s)
{
char strNew[50] = { 0, };
size_t full_len = strlen(s);
size_t half_len = full_len / 2;
for (size_t i = 0; i < half_len; i++) {
strNew[i] = s[i];
}
for (size_t j = half_len; j < full_len; j++) {
if (strNew[j - half_len] != s[j]) { // x != y is clearer than !(x == y)
return 0;
}
}
return 1;
}
In fact, once you have appreciated why you need to subtract that "half length" from the j index of strNew, you can remove the need for that temporary copy completely and just use the modified j as an index into the original string:
int doubleString(char* s)
{
size_t full_len = strlen(s);
size_t half_len = full_len / 2;
for (size_t j = half_len; j < full_len; j++) {
if (s[j - half_len] != s[j]) { // x != y is clearer than !(x == y)
return 0;
}
}
return 1;
}
This loop
for(int j=strlen(s)/2;j<strlen(s);j++){
if(!(strNew[j]==s[j])){
true=0;
}
}
is incorrect. The index in the array strNew shall start from 0 instead of the value of the expression strlen( s ) / 2.
But in any case your approach is incorrect because at least you are using an intermediate array with the magic number 50. The user can pass to the function a string of any length.
char strNew[50];
The function can look much simpler.
For example
int doubleString( const char *s )
{
int double_string = 0;
size_t n = 0;
if ( ( double_string = *s != '\0' && ( n = strlen( s ) ) % 2 == 0 ) )
{
double_string = memcmp( s, s + n / 2, n / 2 ) == 0;
}
return double_string;
}
That is the function at first checks that the passed string is not empty and its length is an even number. If so then the function compares two halves of the string.
Here is a demonstration program.
#include <stdio.h>
#include <string.h>
int doubleString( const char *s )
{
int double_string = 0;
size_t n = 0;
if (( double_string = *s != '\0' && ( n = strlen( s ) ) % 2 == 0 ))
{
double_string = memcmp( s, s + n / 2, n / 2 ) == 0;
}
return double_string;
}
int main( void )
{
printf( "doubleString( \"\" ) = %d\n", doubleString( "" ) );
printf( "doubleString( \"HelloHello\" ) = %d\n", doubleString( "HelloHello" ) );
printf( "doubleString( \"Hello Hello\" ) = %d\n", doubleString( "Hello Hello" ) );
}
The program output is
doubleString( "" ) = 0
doubleString( "HelloHello" ) = 1
doubleString( "Hello Hello" ) = 0
Pay attention to that the function parameter should have the qualifier const because the passed string is not changed within the function. And you will be able to call the function with constant arrays without the need to defined one more function for constant character arrays.
it's better to do it with a while loop since you don't always have to iterate through all the elements of the string but since you want the for loop version here it is (C++ version):
int doubleString(string s){
int s_length = s.length();
if(s_length%2 != 0) {
return 0;
}
for (int i = 0; i < s_length/2; i++) {
if (s[i] != s[s_length/2 + i]){
return 0;
}
}
return 1;
}

Digit Frequency Program (HackerRank)

I'm trying to compare each character of the given string with numbers 0 to 9, and on successful comparison, increment the count variable. Finally, printing the value of count variable for each of the numbers.
But these method isn't working out. Can't figure out why.
int main() {
char *s;
s = malloc(1024 * sizeof(char));
scanf("%[^\n]", s);
int i,j,count=0;
for(i=0;i<=9;i++)
{
for(j=0;j<strlen(s);j++)
{
if(s[j]==i)
{
count++;
}
}
printf("%d ",count);
}
return 0;
}
Finally, printing the value of count variable for each of the numbers.
So you need an array to store counters for each digit. It is strange that zero is excluded from counted digits.
In this if statement
if(s[j]==i)
you have to write at least
if( s[j] - '0' == i )
And moreover this loop
for(i=0;i<=9;i++)
also tries to count zeroes though you wrote that to count only digits 1-9 inclusively.
Your approach is inefficient because you are traversing the same character array several times.
And there is no sense to allocate a character array dynamically.
The program can look the following way
#include <stdio.h>
int main(void)
{
enum { M = 9, N = 1024 };
char s[N];
s[0] = '\0';
size_t counter[M] = { 0 };
fgets( s, N, stdin );
for ( const char *p = s; *p; ++p )
{
if ( '0' < *p && *p <= '9' )
{
++counter[*p - '0' - 1];
}
}
for ( size_t i = 0; i < M; i++ )
{
printf( "%zu ", counter[i] );
}
putchar( '\n' );
return 0;
}
If to enter for example a string like
12345678987654321246897531
then the output will be
3 3 3 3 3 3 3 3 2
In fact the character array is redundant for this task. Moreover it restricts the length of the entered sequence of digits. You could write the program without using a character array. For example
#include <stdio.h>
int main(void)
{
enum { M = 9, N = 1024 };
size_t counter[M] = { 0 };
for ( int c; ( c = getchar() ) != EOF && c != '\n'; )
{
if ( '0' < c && c <= '9' )
{
++counter[c - '0' - 1];
}
}
for ( size_t i = 0; i < M; i++ )
{
printf( "%zu ", counter[i] );
}
putchar( '\n' );
return 0;
}
if(s[j]==i) <<<<<<<<<
{
count++;
}
You are comparing the ordinal value of the character to an integer in the range 0 to 9. Which is not what you want.
You can convert a digit to int with this method:
char c = '5';
int x = c - '0';
So in your case it would be:
if(s[j] -'0' ==i)
{
count++;
}
In C a character value is a number, but it is not the number you are expecting here. When we have the character '2' and we check what it is equal to as a number we are really asking what the ASCII code of '2' is which in this case would be 50. You need to adjust your code so it converts the ASCII code into a numeric representation so 50 becomes 2. It is quite simple simply change your code so it looks like this
if((s[j] - '0') == i){
This works because the ASCII code of 0 is 48, the ASCII code of 1 is 49, etc etc.
TL;DR In C a character value is not equal to it's numeric value. You need to convert '5' to 5. To do this you adjust your code so you subtract the '0' character from your numeric character.

Comparing substring of a character array with another character array in C

I have two characters arrays called arraypi and arraye containing numbers that I read from a file. Each have 1,000,000 characters. I need to start from the first character in arraye (In this case, 7) and search for it in arraypi. If 7 exists in arraypi then I have to search for the next substring of arraye(in this case, 71). Then search for 718, 7182 and so on until the substring does not exist in arraypi. Then I have to simply put the length of the biggest substring in a integer variable and print it.
Worth mentioning that arraypi contains a newline every 50 characters whereas arraye contains a newline every 80 although I don't think that will be problem right?
I tried thinking about a way to accomplish this but so far I haven't thought of something.
I am not absolutely sure if I got this right. I have something like this on my mind:
Assume that we have the whole arraypi is in a browser
You use the key combination ctrl+f for find
Start typing the contents of arraye letter by letter until you see the red no match
You want the number of characters you were able to type until then
If that's right, then an algorithm like the following should do the trick:
#include <stdio.h>
#define iswhitespace(X) ((X) == '\n' || (X) == ' ' || (X) == '\t')
int main( ) {
char e[1000] = "somet\n\nhing";
char pi[1000] = "some other t\nhing\t som\neth\n\ning";
int longestlen = 0;
int longestx = 0;
int pix = 0;
int ex = 0;
int piwhitespace = 0; // <-- added
int ewhitespace = 0; // <-- these
while ( pix + ex + piwhitespace < 1000 ) {
// added the following 4 lines to make it whitespace insensitive
while ( iswhitespace(e[ex + ewhitespace]) )
ewhitespace++;
while ( iswhitespace(pi[pix + ex + piwhitespace]) )
piwhitespace++;
if ( e[ex + ewhitespace] != '\0' && pi[pix + ex + piwhitespace] != '\0' && pi[pix + ex + piwhitespace] == e[ex + ewhitespace] ) {
// the following 4 lines are for obtaining correct longestx value
if ( ex == 0 ) {
pix += piwhitespace;
piwhitespace = 0;
}
ex++;
}
else {
if ( ex > longestlen ) {
longestlen = ex;
longestx = pix;
}
pix += piwhitespace + 1;
piwhitespace = 0;
// the two lines above could be replaced with
// pix++;
// and it would work just fine, the injection is unnecessary here
ex = 0;
ewhitespace = 0;
}
}
printf( "Longest sqn is %d chars long starting at %d", longestlen, longestx + 1 );
putchar( 10 );
return 0;
}
What's happening there is, the loop searches for a starting point for match first. Until it finds a match, it increments the index for the array being examined. When it finds a starting point, it then starts incrementing the index for the array containing the search term, keeping the other index constant.
Until a next mismatch, which is when a record-check is made, search term index is reset and examinee index starts getting incremented once again.
I hope this helps, somehow, hopefully more than resolving this single-time struggle.
Edit:
Changed the code to disregard white space characters.
Okay, since you apparently weren't really wanting this for arrays, but rather for two files with text inside, here's an appropriate solution to achieve that:
#include <stdio.h>
#define iswhitespace(X) ((X) == '\n' || (X) == ' ' || (X) == '\t')
int main( ) {
FILE * e;
FILE * pi;
if ( ( e = fopen( "e", "r" ) ) == NULL ) {
printf( "failure at line %d\n", __LINE__ );
return -1;
}
if ( ( pi = fopen( "pi", "r" ) ) == NULL ) {
printf( "failure at line %d\n", __LINE__ );
return -1;
}
int curre = fgetc( e );
int currpi = fgetc( pi );
int currentlength = 0;
int longestlength = 0;
int longestindex = 0;
int whitespaces = 0;
fpos_t startpoint;
if ( curre == EOF || currpi == EOF ) {
printf( "either one of the files are empty\n" );
return -1;
}
while ( 1 ) {
while ( iswhitespace( currpi ) )
currpi = fgetc( pi );
while ( iswhitespace( curre ) )
curre = fgetc( e );
if ( curre == currpi && currpi != EOF ) {
if ( currentlength == 0 && fgetpos( pi, &startpoint ) ) {
printf( "failure at line %d\n", __LINE__ );
return -1;
}
currentlength++;
curre = fgetc( e );
}
else if ( currentlength != 0 ) {
if ( currentlength > longestlength ) {
longestlength = currentlength;
longestindex = startpoint;
}
if ( curre == EOF ) {
printf( "Complete match!\n" );
break;
}
fsetpos( pi, &startpoint );
rewind( e );
curre = fgetc( e );
currentlength = 0;
}
if ( currpi == EOF )
break;
currpi = fgetc( pi );
}
printf( "Longest sequence is %d characters long starting at %d",
longestlength, longestindex );
putchar( 10 );
return 0;
}
It searches for a starting point, stores that starting point to return back to after determining the length of the current match. Determines the length of the current match, disregarding the whitespace on the way. Updates the record length if necessary, completely rewinds the search term file, partially-rewinds the examinee file back to the stored position.
Here's my e file:
somet
hing
And here is my pi file:
some other nhing som
eth
ing
And here's the output I get:
Complete match!
Longest sequence is 9 characters long starting at 20
By the way, fread and fwrite do not function humanly intuitive, as far as I remember. You can think of it like, computer uses a language that it itself understands while issuing those functions.
You can use strstr() function.Consider using it in a loop with return string as one of the argument.

search for '\n in char pointer use c

I am trying to loop a char*str use this to find out how many lines:
char *str = "test1\ntest2\ntest3";
int lines = 0;
for(int i = 0 ; i < ?? ; i ++ )
{
if(str[i] == '\n') {
lines++;
}
}
I am not sure what to put at the ??, the question is :
1.I mean do I need to use strlen(str) + 1 ?
2.when the str is "test1\ntest2\ntest3\n",does the code still calculate correct lines?
I am using gcc by the way,thanks
every literal string ends with \0 which is a null character..It depicts the end of the string
So,
You can do this
for(int i = 0 ; str[i]!='\0' ; i ++ )
To extend the already-existent good answers: the idiomatic way for looping through a C string is
const char *s = "abc\ndef\nghi\n";
int lines = 0;
int nonempty = 0;
while (*s) {
nonempty = 1;
if (*s++ == '\n') lines++;
}
If you don't want to count the last empty line as a separate line, then add
if (nonempty && s[-1] == '\n' && lines > 0) lines--;
after the while loop.
Take the length of the string and iterate through all characters.
const unsigned long length=strlen(str);
for(int i = 0 ; i < length ; i ++ )
{
if(str[i] == '\n') {
lines++;
}
}
The following will deliver the same result regardless if the last character is a newline or not.
char *abc = "test1\ntest2\ntest3";
int lines = 0;
{
bool lastWasNewline = true;
char * p = abc;
for (; *p; ++p) {
if (lastWasNewline) ++lines;
lastWasNewline = *p == '\n';
}
}
1.I mean do I need to use strlen(str) + 1 ?
no, just use str[i] for i < ??, this tests if that is the 0 character which terminates the string
2.when the abc is "test1\ntest2\ntest3\n",does the code still calculate correct lines?
no, you code assumes that the input is broken into one input line per buffer line[j].
in place of ?? put strlen(abc) and make sure #include <string.h>
For better efficiency do
int length= strlen(abc);
and then use i < length
Or use str[i]!= '\0'

ANSI C splitting string

Hey there!
I'm stuck on an ANSI C problem which I think should be pretty trivial (it is at least in any modern language :/).
The (temporary) goal of my script is to split a string (array of char) of 6 characters ("123:45") which represents a timestamp minutes:seconds (for audio files so it's ok to have 120 minutes) into just the minutes and just the seconds.
I tried several approaches - a general one with looking for the ":" and a hardcoded one just splitting the string by indices but none seem to work.
void _splitstr ( char *instr, int index, char *outstr ) {
char temp[3];
int i;
int strl = strlen ( instr );
if ( index == 0 ) {
for ( i = 0; i < 3; ++i ) {
if ( temp[i] != '\0' ) {
temp[i] = instr[i];
}
}
} else if ( index == 1 ) {
for ( i = 6; i > 3; i-- ) {
temp[i] = instr[i];
}
}
strcpy ( outstr, temp );
}
Another "funny" thing is that the string length of an char[3] is 6 or 9 and never actually 3. What's wrong with that?
How about using sscanf(). As simple as it can get.
char time[] = "123:45";
int minutes, seconds;
sscanf(time, "%d:%d", &minutes, &seconds);
This works best if you can be sure that time string syntax is always valid. Otherwise you must add check for that. On success, sscanf function returns the number of items succesfully read so it's pretty easy to detect errors too.
Working example: http://ideone.com/vVoBI
How about...
int seconds, minutes;
minutes = atoi(instr);
while(*instr != ':' && *++instr != '\0');
seconds = atoi(instr);
Should be pretty fast.
You have basically three options
change the input string (can't be a string literal)
copy data to output strings (input can be a literal)
transform sequences of characters to numbers
Changing the input string implies transforming "123:45" to "123\0" "45" with an embedded null.
Copying data implies managing storage for the copy.
Transforming sequences of characters implies using, for example, strtol.
You aren't putting a terminating null on your string in temp[], so when you do a strlen(temp), you are accessing arbitrary memory.
Using your known lengths, you can use something like this:
char temp[4];
if (index==0)
{
strncpy(temp, instr, 3);
temp[3] = 0;
}
else if (index==1)
{
strncpy(temp, instr+4, 2);
temp[2] = 0;
}
strcpy(outstr, temp);
But, I'll caution that I've skipped all sorts of checking for valid lengths in instr and outstr.
you can try something like that:
void break_string(const char* input, char* hours, char* minutes)
{
if(input == 0 || hours == 0 || minutes == 0)
return;
while(*input != ':')
*hours++ = *input++;
*hours = '\0';
++input;
while(*minutes++ = *input++);
return;
}
Here is the same function a bit simplified:
void break_string(const char* input, char* hours, char* minutes)
{
if(input == 0 || hours == 0 || minutes == 0)
return;
while(*input != ':')
{
*hours = *input;
++hours;
++input;
}
*hours = '\0';
++input; //ignore the ':' part
while(*input)
{
*minutes = *input;
++minutes;
++input;
}
*minutes = '\0';
return;
}
int main()
{
char* test = "123:45";
char* minutes = malloc( sizeof(char) * 12 );
char* hours = malloc( sizeof(char) * 12 );
break_string( test , hours , minutes );
printf("%s , %s \n" , hours , minutes );
//...
free( minutes );
free( hours ) ;
}
This?
char *mins, *secs;
mins = str;
while(*(++str) != ':');
str[0] = '\0';
secs = s + 1;
Here's one way, I have ignore the "index" argument above:
#include <stdio.h>
#include <string.h>
void _splitstr ( char *instr, char *outstr ) {
char temp[10];
char* end = strchr(instr, ':');
int i = 0;
if(end != 0) {
while(instr != end)
temp[i++] = *instr++;
temp[i] = '\0';
strcpy(outstr, temp);
} else {
outstr = '\0';
}
}

Resources