Character comparison in C fails - c

I'm trying to parse a Fen String (char *starting_fen), but it doesn't seem to be working.
starting_fen: rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1
void init_board(char *starting_fen)
{
int rank = 7, file = 0, fen_length = strlen(starting_fen);
for (int i = 0; i < fen_length; i++)
{
if (starting_fen[i], "/") // <-- works for all characters?
{
printf("SYMBOL # idx %d ==> '%c'\n", i, starting_fen[i]);
// file = 0;
// rank--;
}
}
}
This is my output:
SYMBOL # idx 0 ==> 'r'
SYMBOL # idx 1 ==> 'n'
SYMBOL # idx 2 ==> 'b'
//...
SYMBOL # idx 53 ==> '0'
SYMBOL # idx 54 ==> ' '
SYMBOL # idx 55 ==> '1'
I tried using strcmp (if (strcmp(starting_fen[i], "/"))) but got a Segmentation fault...

I answer this because it is a funny bug. Here:
if (starting_fen[i], "/")
You are calling , operator. So it returns "/" which always will be evaluated to true (Since it is a address which will have a value not equal to 0). Your code need to be like this:
if (starting_fen[i] == '/')
So 2 changes:
You need == operator to check equality.
Characters are identified by ' not ".

This fails:
if (starting_fen[i], "/") {
because starting_fen[i], "/" is always "/" which is not null. See the wikipdia page about the comma operator
This fails:
if (strcmp(starting_fen[i], "/")) {
Because starting_fen[i] will be a char, not a pointer to a string. Thus it will try to read a location in early memory and fail.
This fails:
if (starting_fen[i] == "/") {
Since you are trying to compare a char to a pointer.
This is correct:
if (starting_fen[i] == '/') {

You can save yourself a lot of grief if you use proven standard library functions.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char *starting_fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
printf( "Given: '%s'\n", starting_fen );
char *rank[8];
char *cp = starting_fen;
for( int i = 0; i < sizeof rank/sizeof rank[0]; i++ ) {
rank[ i ] = cp;
cp = strpbrk( cp, "/ " ); // standard library function
*cp++ = '\0';
printf( "%d '%s'\n", i, rank[ i ] );
}
printf( "The rest: '%s'\n", cp );
return 0;
}
Output:
Given: 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1'
0 'rnbqkbnr'
1 'pppppppp'
2 '8'
3 '8'
4 '8'
5 '8'
6 'PPPPPPPP'
7 'RNBQKBNR'
The rest: 'w KQkq - 0 1'
You may want to start the array index with 7 and count down to 0. That's for you to decide.

Related

for loop is only printing last iteration

I am trying to write a C program that takes a string input from a user and then looks into the input to count the frequency of all the integers in the string. So suppose if the user gives the input:
a11472o5t6
the output would be :
0 2 1 0 1 1 1 1 0 0
my approach involves comparing every character of the string to all 10 digits one by one and if any the character is equal to the digit, it would increment the isdigit number by 1.
the code I wrote for the same is as follows:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
int is1 = 0; //initialise integers for checking
int is2 = 0;
int is3 = 0;
int is4 = 0;
int is5 = 0;
int is6 = 0;
int is7 = 0;
int is8 = 0;
int is9 = 0;
int is0 = 0;
int main()
{
char s[100]; //initialise array for string
scanf("%s", s); //scan string input
//now all characters of the string are stored in the array s
for (int i = 0; i < strlen(s); i++) //loop to iterate over all the elements in the array
{
if (strcmp(&s[i], "0") == 0)
{
is0 = is0 + 1;
}
if (strcmp(&s[i], "1") == 0)
{
is1 = is1 + 1;
}
if (strcmp(&s[i], "2") == 0)
{
is2 = is2 + 1;
}
if (strcmp(&s[i], "3") == 0)
{
is3 = is3 + 1;
}
if (strcmp(&s[i], "4") == 0)
{
is4 = is4 + 1;
//printf("%d", is4);
}
if (strcmp(&s[i], "5") == 0)
{
is5 = is5 + 1;
}
if (strcmp(&s[i], "6") == 0)
{
is6 = is6 + 1;
}
if (strcmp(&s[i], "7") == 0)
{
is7 = is7 + 1;
}
if (strcmp(&s[i], "8") == 0)
{
is8 = is8 + 1;
}
if (strcmp(&s[i], "9") == 0)
{
is9 = is9 + 1;
}
}
printf("%d ", is0);
printf("%d ", is1);
printf("%d ", is2);
printf("%d ", is3);
printf("%d ", is4);
printf("%d ", is5);
printf("%d ", is6);
printf("%d ", is7);
printf("%d ", is8);
printf("%d ", is9);
}
I expected the code to iterate over and over for the entire length of the string and and update values of the isdigit series every time a number was successfully found. However whenever I run the code only the last digit seems to find its place in the output .
for example if I type 54 as an input the expected output is
0 0 0 0 1 1 0 0 0 0
however the output my code seems to be giving is
0 0 0 0 1 0 0 0 0 0
likewise the number 45 also has the same expected output
0 0 0 0 1 1 0 0 0 0
but the output I am receiving is
0 0 0 0 0 1 0 0 0 0
which looks like the code overwrites any operation that occurred in the previous iteration, but I can't seem to understand why and how to fix it.
On my part I checked if the characters were being called properly one by one and that all characters were being compared, where I found no problem. I also looked up other answers on stack overflow and elsewhere, but was I am a beginner and most answers were written in reference to languages that I can't understand, so I was unable to relate to the solution they were being told. the closest I got was someone who was using a single variable repetitively thus overwriting it in each iteration. however I have declared sufficient variables( one for each digit from 0-9), so that shouldn't be the problem in my code either.
while I know this question could be solved easily using arrays, I would like to know what I was doing wrong here to avoid any such mistakes in the future.
When you do if (strcmp(&s[i],"1")==0) you are comparing strings, not individual characters, which is why only the last character is counted. It's the only one matching.
Example:
If s == "a11472o5t6" and you use strcmp(&s[1], "1"), you would be comparing the string "11472o5t6" with the string "1", which clearly will not be equal.
You want if(s[i] == '1') etc. to do the comparisons of individual characters instead.
And you are correct about using arrays instead. It'd certainly be easier.
Example:
#include <ctype.h>
#include <stdio.h>
int main() {
const char *str = "a11472o5t6";
int ints[10] = {0};
for (const char *chptr = str; *chptr != '\0'; ++chptr) {
if(isdigit((unsigned char) *chptr)) ++ints[*chptr - '0'];
}
for (int i = 0; i < 10; ++i) printf("%d %d\n", i, ints[i]);
}
Output:
0 0
1 2
2 1
3 0
4 1
5 1
6 1
7 1
8 0
9 0

Printing array partially in C

I am a newbie to C and want to print some special elements of an array.
//Partial code here
char aaa[18] ;
int i = 0;
while(i < 18) {
aaa[i] = '#' ;
printf("%c", aaa[i]) ;
i = i + 4 ;
}
It's supposed to prints 4 # of aaa[0] ,aaa[4],aaa[8],aaa[12],aaa[16]. But it is not. It is printing them in a row like #####. But I don't want those .
I'm assuming you want to eventually print a string and get output like this
"# # # # # "
minus the quotes.
You can do this by filling in a null-terminated string and then printfing that, like so:
// +1 for space for a null terminator
// = {0}; fills the array with 0s
char aaa[18+1] = {0};
// for loop is more idiomatic for looping over an array of known size
for (int i = 0; i < 18; i += 4) {
// if the remainder of dividing i by 4 is equal to 0
if (i % 4 == 0) {
// then put a '#' character in the array at aaa[i]
aaa[i] = '#';
} else {
// otherwise put a ' ' character in the array at aaa[i]
aaa[i] = ' ';
}
}
printf("%s", aaa);
As you're adding 4 to the i variable in each cycle you're printing the positions 0, 4, 8, 12, 16 of the array consecutively.
If you want to print the vector with # as the 4*nth element you should do something like:
while( i < 18 )
{
if( i % 4 == 0 )
{
aaa[i] = '#';
printf("%c" ,aaa[i]);
}
else
printf(" "); // Assuming you want a space in between prints
i++;
}

Pass string to main and break up into array

I am passing arguments to main with this code:
#include <stdio.h>
int main(int argc, char ** argv)
{
int i = 1;
for(i = 1; i < argc; i++)
printf("%c", argv[i]);
return 0;
}
So I use ./test 218 abc 392990xFF[w2 dlx which works fine. However, the array is:
arr[1] = "218"
arr[2] = "abc"
arr[3] = "392990xFF[w2"
arr[4] = "dlx"
I want the array to be like this:
arr[0] = '2'
arr[1] = '1'
arr[2] = '8'
arr[3] = 'a'
etc...
How can I achieve this without putting a space after each digit or character?
The arguments passed by the run time environment to the program can be captured by main using int argc, char** argv only. If you have a need to combine them into one large array, you'll need to write the code for that, or print them one character at a time.
int main(int argc, char ** argv)
{
int i = 1;
int j;
int len;
for(i = 1; i < argc; i++)
{
len = strlen(argv[i]);
for ( j = 0; j < len; ++j )
{
printf("%c", argv[i][j]);
}
}
return 0;
}
First of all this is not what it will print -
arr[0] = "218"
arr[1] = "abc"
arr[2] = "392990xFF[w2"
arr[3] = "dlx"
argv[0] will store ./test. And "218" will be on index 1 thus others similarly .
And also printf("%c", argv[i]); .%c expects a char and you pass a string which is incorrect.
Solution could be -
#include <stdio.h>
int main(int argc, char ** argv)
{
int i = 1,j;
for(i = 1; i <argc; i++)
for(j=0;argv[i][j]!='\0';j++)
printf("%c\n", argv[i][j]);
return 0;
}
Rather than a for loop, you can also simply use pointers and while loops instead. There are generally many ways to solve problems in C:
#include <stdio.h>
int main (int argc, char **argv) {
int i = 1;
int j = 0;
while (i < argc) {
char *p = argv[i];
while (*p) {
printf (" arr[%2d] = \"%c\"\n", j++, *p);
p++;
}
i++;
}
return 0;
}
Output
$ ./bin/argvchars 218 abc 392990xFF[w2 dlx
arr[ 0] = "2"
arr[ 1] = "1"
arr[ 2] = "8"
arr[ 3] = "a"
arr[ 4] = "b"
arr[ 5] = "c"
arr[ 6] = "3"
arr[ 7] = "9"
arr[ 8] = "2"
arr[ 9] = "9"
arr[10] = "9"
arr[11] = "0"
arr[12] = "x"
arr[13] = "F"
arr[14] = "F"
arr[15] = "["
arr[16] = "w"
arr[17] = "2"
arr[18] = "d"
arr[19] = "l"
arr[20] = "x"
Determine the total number of characters in all of the strings, then allocate a new character array of that length, and then copy the input characters into the new array.
The last part could take advantage of the sizes you gather in the first part: have an outer loop over all the argument strings, with an inner loop over the characters in each string.
EDIT: Now that I'm not on a mobile device, here's the above in code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char ** argv)
{
//For storing sizes of each input string
int *arg_chars;
//Where the individual characters are stored
char *stored_chars;
/* Determine total number of characters, and store
characters in each word for later re-use */
arg_chars = malloc(argc * sizeof(int));
int total_chars = 0;
//Loop starts at 1 since we don't care about arg 0
for(int i=1; i<argc; i+=1)
{
arg_chars[i] = strlen(argv[i]);
total_chars += arg_chars[i];
printf("Word %d is %d long\n", i, arg_chars[i]);
}
/* Load argument characters into the stored_chars array */
stored_chars = malloc(total_chars * sizeof(char));
int current_char = 0;
//Loop starts at 1 to exclude the program name (arg 0)
for(int i = 1; i < argc; i+=1)
{
printf("Scanning word %d (%s):\n", i, argv[i]);
for(int j = 0; j < arg_chars[i]; j+=1)
{
stored_chars[current_char] = argv[i][j];
printf(" Stored letter %d `%c` (letter %d of word %d)\n", current_char, argv[i][j], j, i);
current_char += 1;
}
}
/* Demonstrate that it's all loaded and accessible in any order */
for(int i=total_chars-1; i >= 0; i-=1)
{
printf("stored_chars[%d] = `%c`\n", i, stored_chars[i]);
}
return 0;
}
Output:
Word 1 is 3 long
Word 2 is 3 long
Word 3 is 12 long
Word 4 is 3 long
Scanning word 1 (218):
Stored letter 0 `2` (letter 0 of word 1)
Stored letter 1 `1` (letter 1 of word 1)
Stored letter 2 `8` (letter 2 of word 1)
Scanning word 2 (abc):
Stored letter 3 `a` (letter 0 of word 2)
Stored letter 4 `b` (letter 1 of word 2)
Stored letter 5 `c` (letter 2 of word 2)
Scanning word 3 (392990xFF[w2):
Stored letter 6 `3` (letter 0 of word 3)
Stored letter 7 `9` (letter 1 of word 3)
Stored letter 8 `2` (letter 2 of word 3)
Stored letter 9 `9` (letter 3 of word 3)
Stored letter 10 `9` (letter 4 of word 3)
Stored letter 11 `0` (letter 5 of word 3)
Stored letter 12 `x` (letter 6 of word 3)
Stored letter 13 `F` (letter 7 of word 3)
Stored letter 14 `F` (letter 8 of word 3)
Stored letter 15 `[` (letter 9 of word 3)
Stored letter 16 `w` (letter 10 of word 3)
Stored letter 17 `2` (letter 11 of word 3)
Scanning word 4 (d1x):
Stored letter 18 `d` (letter 0 of word 4)
Stored letter 19 `1` (letter 1 of word 4)
Stored letter 20 `x` (letter 2 of word 4)
stored_chars[20] = `x`
stored_chars[19] = `1`
stored_chars[18] = `d`
stored_chars[17] = `2`
stored_chars[16] = `w`
stored_chars[15] = `[`
stored_chars[14] = `F`
stored_chars[13] = `F`
stored_chars[12] = `x`
stored_chars[11] = `0`
stored_chars[10] = `9`
stored_chars[9] = `9`
stored_chars[8] = `2`
stored_chars[7] = `9`
stored_chars[6] = `3`
stored_chars[5] = `c`
stored_chars[4] = `b`
stored_chars[3] = `a`
stored_chars[2] = `8`
stored_chars[1] = `1`
stored_chars[0] = `2`

I need to read all integers, mathematical operators, and characters in a string

I have a string which may contain either single integers between 0-9 or mathematical operators (+, -, *, /).
Basically, I need to read in all characters / numbers. I am checking if the character is either +,-,* or /. If not, then I know it is either a number or an invalid character. I am using atoi to convert it to an integer. atoi will return 0 in both cases: if the integer is a 0 OR if it was an invalid character.
How else can I make this distinction?
Check each character with standard isdigit() function before using atoi
Use strtol to perform error detection.
int main (void)
{
int i, j ;
char num_string[] = "1 234 23 45" ;
char tmp [2] = {'\0', '\0'} ;
int length = strlen (num_string) ;
int* values = (int*) malloc (sizeof (int) * length) ;
for ( i = 0, j = 0; i < length; ++i)
{
if ( isdigit (num_string[i] ) )
{
tmp [0] = num_string [i] ;
values [j++] = atoi (tmp) ;
}
}
printf ("\nThe string: %s", num_string) ;
printf ("\nThe integer array which results is: ") ;
for ( i = 0; i < j; ++i)
printf (" %d ", values[i]) ;
return 0 ;
}
input:
1 22 33 4 555
output:
1 2 2 3 3 4 5 5 5

fgets and strtok in a double "for" loop

I'm trying to extract the content of a file into a matrix but the file may look completely differently.
For exemple all these files should give the same result : a 3x3 matrix containing 1,2,3,4,5,6,7,8,9.
1 2 3
4 5 6
7 8 9
1 2 3
4 5 6
7 8 9
1 2 3 4
5
6
7 8
9
1 2 3
$something
$something else
4 5 6
$something else else
7 8 9
Hopefully I know the dimensions of the matrix beforehand as well as the "$" character that indicates that these lines are to be ignored in the current process.
My current algorithm using fscanf works great but It can't work with the "$something" lines.
I figured that I should use the fgets/strtok/sscanf method but there are some issues.
// File* file (already assigned)
char line[32]; //assuming 32 is enough
char* token;
fgets(line,32,file);
token = strtok(line," \t");
for (y=0; y<ySize; y++)
{
for (x=0; x<xSize, x++)
{
if (token[0] == '$') //should use a str function
{
fgets(line,32,file);
token = strtok(line," \t")
x--;
}
else
{
if (we are at the end of the line)
{
fgets(line,32,file);
token = strtok(line," \t")
}
sscanf(token,"%d",&matrix[x][y];
token = strtok(NULL," \t");
}
}
}
Basically I'd like to have some help to write the "if (we are at the end of the line)" condition and some input on my method, is it flawless? Did I correctly thought of the process?
Thank you.
You should use getline instead of fgets to make things easier. The latter is unreliable. The test condition that you are looking for is:
token == NULL;
Check this: "Once the terminating null character of str has been found in a call to strtok, all subsequent calls to this function with a null pointer as the first argument return a null pointer."
You can easily parse without strtok() by using strspn() / strcspn(), and sscanf()s "%n" specifier. Also: there was a ',' in the original code where a ';' should have been.
#include <stdio.h>
#include <string.h>
#define XSIZE 3
#define YSIZE 3
int matrix[XSIZE][YSIZE];
int main(void)
{
char line[200];
int pos,eat,xx,yy, rc;
xx = yy =0;
while ( fgets(line, sizeof line, stdin) ) {
if (line[0] == '$') continue;
for(pos=0; line[pos]; pos += eat) {
pos += strspn(line+pos, " \t\n");
rc =sscanf(line+pos, "%d%n", &matrix[xx][yy], &eat);
if (rc < 1) break;
if (++xx >= XSIZE ) {xx = 0; if(++yy >= YSIZE) goto done; }
}
}
done:
/* show it to the world ... */
for (yy = 0; yy < YSIZE; yy++) {
for (xx = 0; xx < XSIZE; xx++) {
fprintf (stdout, " %d", matrix[xx][yy] );
}
fprintf (stdout, "\n" );
}
return 0;
}

Resources