c check two strings for same characters - c

Im just starting to learn C programming and for exercise i found one task. First i have to scan in two strings. Then i have to compare them character by character and if there are any same characters i have to print out the amount of the same characters.
It has to be done with pointers. So lets i have "boat" and "ship" so the program would return 0. But if it were "boat" and "soap" it would return 2.
This is what i've got so far but when i run it it gives me errors. I put the errors in comments.
Thanks in advance for your help.
#include <stdio.h>
#include <string.h>
int number_of_same_characters(char *, char *);
int main()
{
char * first[100];
char * second[100];
int result = 0;
printf("Enter first string\n");
gets(*first);
printf("Enter second string\n");
gets(*second);
result = number_of_same_characters(*first, *second);
printf("%d\n", result);
return 0;
}
int number_of_same_characters(char *p, char *q){ //i get this error here - error: invalid type argument of unary ‘*’ (have ‘int’)
int counter = 0;
for(int j = 0; *p[j] != '\0' || *q[j] != '\0'; ++j){ //i get this error here - error: invalid type argument of unary ‘*’ (have ‘int’)
if(strcmp(*p[j], *q[j])){
++counter;
}
}
return counter;
}

Mainly you've got a lot of extra *'s littering the program. The variable declarations should be:
char first[100];
char second[100];
The input calls should be†:
gets(first);
gets(second);
The method call should be:
result = number_of_same_characters(first, second);
And finally there shouldn't be any dereferences in the for loop.
for(int j = 0; p[j] != '\0' || q[j] != '\0'; ++j){
if(strcmp(p[j], q[j])){
++counter;
}
}
That'll get you closer, though there are still a couple of problems. As a hint, the || operator is suspect, and you don't need to use strcmp.
† It's worth pointing out that gets() is a dangerous function that can lead to buffer overflows. It's okay to use when you're just starting out, but don't let it become a habit, and don't ever use it in production code!

You defined character arrays incorrectly and incorrectly are using operator *.
Try the following
#include <stdio.h>
#include <string.h>
#define N 100
int number_of_same_characters( const char *, const char * );
int main()
{
char first[N];
char second[N];
int result = 0;
size_t n;
printf( "Enter first string: ");
fgets( first, N, stdin );
n = strlen( first );
if ( first[n - 1] == '\n' ) first[n - 1] = '\0';
printf( "Enter second string: ");
fgets( second, N, stdin );
n = strlen( second );
if ( second[n - 1] == '\n' ) second[n - 1] = '\0';
result = number_of_same_characters( first, second );
printf( "%d\n", result );
return 0;
}
int number_of_same_characters( const char *p, const char *q )
{
int counter = 0;
int i;
for( i = 0; p[i] != '\0' && q[i] != '\0'; ++i )
{
if ( p[i] == q[i] ) ++counter;
}
return counter;
}
If to enter boat and soap then the output will be
2

Related

What's causing a segmentation fault in my code and what I should do to fix it?

I've been getting segmentation fault and I don't know why. I have a feeling that it's caused by the code under if(isPalindrome(str_array[i]) == 0) but I don't know which one and what to do about it.
P.S. I'm still a student so I would appreciate it if the suggestions do not go far from the level of code that I have here.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int isPalindrome(char check[]);
int main() {
int array_size = 5, i;
char *str_array[array_size], *palindrome_array[array_size], str_length[100];
for(i = 0; i < array_size; i++) {
printf("Enter word #%d: ", i+1);
scanf("%[^\n]%*c", str_length); //"%[^\n]%*c : pattern matching - allows inputs to have spaces
str_array[i] = (char*) malloc(sizeof(char) * strlen(str_length));
strcpy(str_array[i],str_length);
if(strcmp(str_array[i],"exit") == 0) {
break;
}
if(isPalindrome(str_array[i]) == 0) {
palindrome_array[i] = (char*) malloc(sizeof(char) * strlen(str_length));
strcpy(palindrome_array[i], str_length);
printf("'%s' is a palindrome \n", palindrome_array[i]);
} else printf("'%s' is NOT a palindrome \n", str_array[i]);
}
//BONUS: prints all the palindrome strings inputted
printf("Your palindrome words are: \n");
for(i = 0; i < array_size; i++) {
printf("%d.)%s \n", i+1, palindrome_array[i]);
}
return 0;
}
int isPalindrome(char check[]) { // from string to individual characters
int middle = strlen(check) / 2; //gets the half of the string's length
int length = strlen(check);
for(int i = 0; i < middle; i++) {
if(check[i] != check[length - i - 1]) {
return 1;
}
}
return 0;
}
There are two main drawbacks.
To allocate a memory for a string you need to reserve space for the terminating zero character '\0' of the string.
So you need to write for example
str_array[i] = (char*) malloc(sizeof(char) * ( strlen(str_length) + 1 ) );
Also the array palindrome_array was not initialized.
char *str_array[array_size], *palindrome_array[array_size], str_length[100];
As not all tested strings are palindromes then some elements of the array still stay uninitialized for some values of the index i due to this if statement
if(isPalindrome(str_array[i]) == 0) {
palindrome_array[i] = (char*) malloc(sizeof(char) * strlen(str_length));
strcpy(palindrome_array[i], str_length);
printf("'%s' is a palindrome \n", palindrome_array[i]);
} else printf("'%s' is NOT a palindrome \n", str_array[i]);
As a result this for loop
for(i = 0; i < array_size; i++) {
printf("%d.)%s \n", i+1, palindrome_array[i]);
}
can invoke undefined behavior.
You need to declare a separate index for the array and to use it instead of the index i.
In fact the array str_array is just redundant. It is enough to use these two arrays.
char *palindrome_array[array_size], str_length[100];
The parameter of the function isPalindrome should be declared with the qualifier const
int isPalindrome( const char check[]);
because the passed string is not changed within the function. Also it is much better when the function returns a npn-zero integer when a string is a palindrome and zero otherwise.
In the call of scanf you should specify the maximum length of the input string and the conversion specifier c should be removed. For example
scanf( " %99[^\n]", str_length );
Also it is unclear why there is used the magic number 5 in your program.
I would write the program the following way
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int isPalindrome( const char s[] )
{
size_t i = 0, n = strlen( s );
while (i < n / 2 && s[i] == s[n - i - 1]) ++i;
return i == n / 2;
}
int main( void )
{
char **p = NULL;
size_t total = 0;
size_t count = 0;
while (1)
{
char s[100];
printf( "Enter a word (to exit just press Enter): " );
if (scanf( "%99[^\n]%*c", s ) != 1 || s[0] == '\0') break;
++total;
if (isPalindrome( s ))
{
printf( "\"%s\" is a palindrome\n", s );
char **tmp = realloc( p, ( count + 1 ) * sizeof( char * ) );
if (tmp == NULL)
{
puts( "Memory allocation error. It is impossible to store the string." );
break;
}
p = tmp;
p[count] = malloc( strlen( s ) + 1 );
if (p[count] == NULL )
{
puts( "Memory allocation error. It is impossible to store the string." );
break;
}
strcpy( p[count], s );
++count;
}
else
{
printf( "\"%s\" is NOT a palindrome\n", s );
}
}
printf( "\nAmong the entered %zu words there are %zu palindrome(s).\n", total, count );
if (count != 0)
{
puts( "They are:" );
for (size_t i = 0; i < count; i++)
{
printf( "\"%s\"\n", p[i] );
}
}
for (size_t i = 0; i < count; i++)
{
free( p[i] );
}
free( p );
}
Its output might look like
Enter a word (to exit just press Enter): 1
"1" is a palindrome
Enter a word (to exit just press Enter): 12
"12" is NOT a palindrome
Enter a word (to exit just press Enter): 122
"122" is NOT a palindrome
Enter a word (to exit just press Enter): 1221
"1221" is a palindrome
Enter a word (to exit just press Enter): 12321
"12321" is a palindrome
Enter a word (to exit just press Enter):
Among the entered 5 words there are 3 palindrome(s).
They are:
"1"
"1221"
"12321"
str_array[i] = (char*) malloc(sizeof(char) * strlen(str_length));
You need one char more to accommodate the null terminating character.
str_array[i] = malloc(sizeof(**str_array) * strlen(str_length) + 1);
strcpy(str_array[i], str_length);
You repeat this error in other places as well. You need to change all wrong allocations.
Some remarks:
Do not cast result of malloc. If the code does not compile you use C++ compiler to compiler C code which is not good.
Use objects instead of types in sizeof
Two problems. There are two occurrences of the
first problem. They are both the same, and are simply that you are not providing enough room for NULL terminator in your string allocations... The error is in this clause:
str_array[i] = (char*) malloc(sizeof(char) * strlen(str_length));
^^^^^^^^^^^^^^^^^^
strcpy(str_array[i],str_length);
Change it to :
str_array[i] = malloc(strlen(str_length)+1);
^^
strcpy(str_array[i],str_length);
...to accommodate need for NULL character.
The same is true for the palindrome test:
palindrome_array[i] = malloc( strlen(str_length)+1);
^^
strcpy(palindrome_array[i], str_length);
Note - applies to both corrections above:
Casting return of malloc() is not necessary and generally not a good idea in C.
And sizeof(char) is always 1 by definition.
second problem occurs when at the end of the inputting of words, and the program attempts to output all palindromes, the array palindrome_array[i] was found to have one less element of array than needed. I will leave troubleshooting that problem to you, but Should you choose to use realloc()at some point, here is a discussion on how to do it correctly.

How can I fix a string that creates some random characters?

The problem is that when I try to reverse a word, there are some words that prints out with unspecified and random characters. I tried to change the string size and the results change (some words make up random characters and some no)
#include <stdio.h>
#include <string.h>
#define LEN 20
void reverse( char w[LEN]);
int main() {
char word[LEN];
reverse(word);
return 0;
}
void reverse (char w[LEN]){
char rev[LEN];
int i,j;
fgets(w, LEN, stdin);
for (i = 0, j = strlen(w)-1; i < strlen(w); i++, j--){
rev[j] = w[i];
}
printf("%s\n", rev);
return;
}
An example of my problem is this:
Input: bathroom
Output: moorhtabp⬧⬧oz⬧
Every time I execute the program, with the same input the output changes.
You simply need to add a '\0' or 0 at the end of rev to terminate it.
for (i = 0, j = strlen(w)-1; i < strlen(w); i++, j--)
{
rev[j] = w[i];
}
rev[i] = 0;
There are a few errors:
fgets() add an newline \n at the end of the string.
You must add a string terminator (0 byte) after the last character.
(Lesser issue) Using strlen() in the loop condition will iterate over the string multiple times. It usually results in O(N^2) algorithms.
Fixes:
Variant A
Use scanf to parse a single word
scanf(" %19s", w)
The specifier %19s scans up to 19 characters and add NULL terminator to fix 20-char-long array
Variant B
Check if the last character of w is \n. If so, replace it with zero.
int L = strlen(w);
if (L > 0 && w[L - 1] == '\n') {
w[--L] = 0;
}
Just put
rev[i] = 0;
at the end.
Just iterate until j is negative, meaning it reached the "one before first" character and there is nothing more to do.
for (i = 0, j = L-1; j >= 0; i++, j--)
rev[j] = w[i];
For starters the call of the function
char word[LEN];
reverse(word);
does not make a sense because neither string is passed to the function. You passed an uninitialized character array.
The function should do only one thing: reverse the passed string.
So the call of fgets should be removed from the function and placed in main.
The function fgets can append the new line character '\n' to the entered string. You need to remove it.
Within the function reverse you forgot to append the terminating zero character '\0' to the reversed string. So this call
printf("%s\n", rev);
invokes undefined behavior.
Also the type of the returned value of the standard C function strlen is the unsigned integer type size_t. You should use this type instaed of the signed integer type int.
And this declaration of the function
void reverse( char w[LEN])
also does not make a great sense because the compiler will adjust it to the following declaration
void reverse( char *w)
and in general the user can pass to the function a string of any length that can be greater than the value LEN.
Below there is a demonstrative program that shows how the function can be written.
#include <stdio.h>
#include <string.h>
char * reverse( char *s )
{
for ( size_t i = 0, n = strlen( s ); i < n / 2; i++ )
{
char c = s[i];
s[i] = s[n - i - 1];
s[n - i - 1] = c;
}
return s;
}
int main(void)
{
enum { N = 20 };
char s[N];
fgets( s, N, stdin );
s[ strcspn( s, "\n" ) ] = '\0';
puts( s );
puts( reverse( s ) );
return 0;
}
If to enter string "Hello World!" then the program output will be
Hello World!
!dlroW olleH

How to detect null values (and replace them) when reading from a file using sscanf [duplicate]

I am currently trying to parse UnicodeData.txt with this format: ftp://ftp.unicode.org/Public/3.0-Update/UnicodeData-3.0.0.html However, I am hitting a problem in that when I try to read, say a line like the following.
something;123D;;LINE TABULATION;
I try to get the data from the fields by code such as the following. The problem is that fields[3] is not getting filled in, and scanf is returning 2. in is the current line.
char fields[4][256];
sscanf(in, "%[^;];%[^;];%[^;];%[^;];%[^;];",
fields[0], fields[1], fields[2], fields[3]);
I know this is the correct implementation of scanf(), but is there a way to get this to work, short of making my own scanf()?
scanf does not handle "empty" fields. So you will have to parse it on your own.
The following solution is:
fast, as it uses strchr rather than the quite slow sscanf
flexible, as it will detect an arbitrary number of fields, up to a given maximum.
The function parse extracts fields from the input str, separated by semi-colons. Four semi-colons give five fields, some or all of which can be blank. No provision is made for escaping the semi-colons.
#include <stdio.h>
#include <string.h>
static int parse(char *str, char *out[], int max_num) {
int num = 0;
out[num++] = str;
while (num < max_num && str && (str = strchr(str, ';'))) {
*str = 0; // nul-terminate previous field
out[num++] = ++str; // save start of next field
}
return num;
}
int main(void) {
char test[] = "something;123D;;LINE TABULATION;";
char *field[99];
int num = parse(test, field, 99);
int i;
for (i = 0; i < num; i++)
printf("[%s]", field[i]);
printf("\n");
return 0;
}
The output of this test program is:
[something][123D][][LINE TABULATION][]
Update: A slightly shorter version, which doesn't require an extra array to store the start of each substring, is:
#include <stdio.h>
#include <string.h>
static int replaceSemicolonsWithNuls(char *p) {
int num = 0;
while ((p = strchr(p, ';'))) {
*p++ = 0;
num++;
}
return num;
}
int main(void) {
char test[] = "something;123D;;LINE TABULATION;";
int num = replaceSemicolonsWithNuls(test);
int i;
char *p = test;
for (i = 0; i < num; i++, p += strlen(p) + 1)
printf("[%s]", p);
printf("\n");
return 0;
}
Just in case you would like to consider this following alternative, using scanfs and "%n" format-specifier, used for reading in how many characters have been read by far, into an integer:
#include <stdio.h>
#define N 4
int main( ){
char * str = "something;123D;;LINE TABULATION;";
char * wanderer = str;
char fields[N][256] = { 0 };
int n;
for ( int i = 0; i < N; i++ ) {
n = 0;
printf( "%d ", sscanf( wanderer, "%255[^;]%n", fields[i], &n ) );
wanderer += n + 1;
}
putchar( 10 );
for ( int i = 0; i < N; i++ )
printf( "%d: %s\n", i, fields[i] );
getchar( );
return 0;
}
On every cycle, it reads maximum of 255 characters into the corresponding fields[i], until it encounters a delimiter semicolon ;. After reading them, it reads in how many characters it had read, into the n, which had been zeroed (oh my...) beforehand.
It increases the pointer that points to the string by the amount of characters read, plus one for the delimiter semicolon.
printf for the return value of sscanf, and the printing of the result is just for demonstration purposes. You can see the code working on http://codepad.org/kae8smPF without the getchar(); and with for declaration moved outside for C90 compliance.
I don't think sscanf will do what you need: sscanf format %[^;] will match a non-empty sequence of not-semicolon characters. The alternative would be using readline with the separator being ';', like:
#include <iostream>
#include <sstream>
#include <string>
int main() {
using namespace std;
istringstream i { "something;123D;;LINE TABULATION;\nsomething;123D;;LINE TABULATION;\nsomething;123D;;LINE TABULATION;\n" };
string a, b, c, d, newline;
while( getline(i, a, ';') && getline(i, b, ';') && getline(i, c, ';') && getline (i, d, ';') && getline(i, newline) )
cout << d << ',' << c << '-' << b << ':' << a << endl;
}
(I have only seen you took the c++ tag off this question now, if your problem is c-only, I have another solution, below:)
#include <string.h>
#include <stdio.h>
int main() {
typedef char buffer[2048];
buffer line;
while( fgets(line, sizeof(line), stdin) > 0 ) {
printf("(%s)\n", line);
char *end = line;
char *s1 = *end == ';' ? (*end = '\0'), end++ : strtok_r(end, ";", &end);
char *s2 = *end == ';' ? (*end = '\0'), end++ : strtok_r(end, ";", &end);
char *s3 = *end == ';' ? (*end = '\0'), end++ : strtok_r(end, ";", &end);
char *s4 = *end == ';' ? (*end = '\0'), end++ : strtok_r(end, ";", &end);
printf("[%s][%s][%s][%s]\n", s4, s3, s2, s1);
}
}

C programming, segmentation fault core dump

I am trying to make a program which takes in a input of "Hello" and outputs "olleH" from reversing the order of the characters. However I keep getting a segmentation fault and I don't understand why
#include <stdio.h>
#include<string.h>
int main()
{
int i;
int size;
char s[100],a[100];
printf("Enter the word you want to get reversed: ");
scanf("%s",s);
while(s[i]!='\0')
{
a[i]=s[i];
i++;
}
size=sizeof(s);
while(i<sizeof(s))
{
s[i]=a[size];
}
printf("The reversed string is : %s",s);
}
Another simple way to reverse string.
Try this:
while(s[++i]!='\0'); // find the size of string
while(i>=0)
a[j++] = s[--i]; // reverse the string
a[j]='\0';
printf("The reversed string is : %s",a);
This while loop
while(i<sizeof(s))
{
s[i]=a[size];
}
does not make sense because index i has a value that points to outside the entered string (provided that it was initially correctly initialized) and the loop is infinite because i is not changed (and was not initially initialized) in the loop and also the right hand expression of this statement
s[i]=a[size];
is always the same and again refers memory outside the array.
Take into account that neither function declared in <string.h> is used in the program. So the header may be removed.
The program can look the following way
#include <stdio.h>
#define N 100
int main()
{
char s[N], d[N];
printf( "Enter the word you want to get reversed: " );
fgets( s, N, stdin );
size_t n = 0;
while ( s[n] != '\0' && s[n] != '\n' ) n++;
for ( size_t i = 0; i != n; i++ ) d[i] = s[n-i-1];
d[n] = '\0';
printf( "The reversed string is : %s\n", d );
return 0;
}
You can reverse a string without using an auxiliary array. For example
#include <stdio.h>
#define N 100
int main()
{
char s[N];
printf( "Enter the word you want to get reversed: " );
fgets( s, N, stdin );
size_t n = 0;
while ( s[n] != '\0' && s[n] != '\n' ) n++;
s[n] = '\0';
for ( size_t i = 0; i < n / 2; i++ )
{
char c = s[i];
s[i] = s[n-i-1];
s[n-i-1] = c;
}
printf( "The reversed string is : %s\n", s );
return 0;
}
The problem is in this part:
size=sizeof(s);
while(i<sizeof(s))
{
s[i]=a[size];
}
sizeof(s) will be 100 whereas the string you read from input can be less than that -- which would be undefined if you access uninitialized parts of s. So, you want to use strlen() to get the actual size of the string and use it to reverse.
Notice that scanf() is unsafe as it's written (what if you input more than 100 chars?). Suggest using fgets() instead.

To insert a substring in the given string:Error:15 [Warning] return makes integer from pointer without a cast

I wish to insert a substring in the main string from the given position c which is user entered but i am constantly getting this warning
Header File:
char insstr(char a[100],char b[100],int c){
int i,j,t;
while(b[i]!='\0'){
i++;
}
i=t;
i=0;
for(j=c;j<t;j++){
a[j]=b[i];
i++;
}
return a;
}
Main File:
#include<stdio.h>
#include"Q7.h"
main(){
char x[100],y[100],f;
printf("Enter the main string \n");
gets(x);
printf("Enter the substring \n");
gets(y);
printf("Enter the position from where you want to enter the string");
scanf("%d",f);
printf("%s",insstr(x,y,f));
}
Strings are usually represented as char arrays i.e. char[] or char*. Since you are returning a string from the function, the return type should be char*.
char* insstr(char a[100],char b[100],int c)
{
/* ... */
}
You don't initialize i in insstr() before using it. This:
int i,j,t;
while(b[i]!='\0')
{
i++;
}
Should be:
int i,j,t;
i = 0;
while(b[i] != '\0')
{
i++;
}
Or, instead of reinventing the wheel, you should be using strlen(b) instead.
This is just wrong:
i=t;
i=0;
You didn't initialize t, and you are assigning to i twice. You end up obliterating whatever was stored in i. And of course, you are overwriting the contents of a without taking care of what was there. You are not inserting a string into a, you are replacing part of it with b. And then of course, as mentioned in other comments and answers, the return value should be char *.
Why not something as simple as this:
char *insstr(char *a, char *b, int c)
{
size_t a_len = strlen(a);
size_t b_len = strlen(b);
strcat(a, b);
reverse(a+c, a_len-c);
reverse(a+a_len, strlen(b));
reverse(a+c, a_len-c+b_len);
return a;
}
Where reverse() is:
void reverse(char *str, size_t len)
{
size_t i = 0, j = len-1;
while (i < j)
{
char tmp = str[i];
str[i] = str[j];
str[j] = tmp;
i++;
j--;
}
}
The algorithm works by concatenating b to a and then doing the appropriate swaps to move b into the right spot. In general, you can think of a as a string that can be decomposed into two blocks, ac, where c is the block after the insertion point where b will stay. When you concatenate b to the original string, you get acb. Moving b to the spot before c is a matter of reversing c, reversing b, so that you get a c_r b_r, and then you reverse c_r b_r, getting bc - just what you wanted.
A small example of how to use it:
int main(void)
{
char str1[100] = "Hello!";
char str2[] = ", world";
insstr(str1, str2, 5);
printf("%s\n", str1);
return 0;
}
This prints:
Hello, world!
Remember that you must make sure that a is indeed large enough to hold b. In general, you should pass the size of a as an argument, so that you can take appropriate action if a is not big enough, or, alternatively, you can make your code ensure that insstr() is not called if a is not big enough.
And please don't use gets(). Always use fgets(). It doesn't hurt, it is not complex, and it shows that you care.
NOTE: this idea is generalized in the book Programming Pearls as an efficient and elegant way to implement string rotations (which is what you want after appending b). Off the top of my head, I think it is mentioned in the "Aha! Algorithms" column.
#include<stdio.h>
#include<stdlib.h>
int insstr ( char *str, char *ins, int at) {
int each;
int len = 0;
int lenstr = 0;
int lenins = 0;
while ( str[lenstr] != '\0') {
lenstr++;
}
while ( ins[lenins] != '\0') {
lenins++;
}
if ( at > lenstr) {
at = lenstr; // force at to length of str if needed
}
len = at;
for ( each = 0; each <= lenins; each++) {
str[len] = ins[each]; // append ins onto str
len++;
}
return 1; // return true
}
int main() {
char input[300];
char substr[300];
char position[300];
int insert;
int each;
printf ( "Enter a string.\n");
fgets ( input, sizeof ( input), stdin);
each = 0;
while ( input[each] != '\n') {
each++;
}
input[each] = '\0'; // remove new-line
printf ( "Enter sub-string.\n");
fgets ( substr, sizeof ( substr), stdin);
each = 0;
while ( substr[each] != '\n') {
each++;
}
substr[each] = '\0'; // remove new-line
printf ( "Enter position to insert sub-string.\n");
fgets ( position, sizeof ( position), stdin);
insert = atoi ( position); // make position an integer
if ( insstr ( input, substr, insert)) {
printf ( "%s\n", input); // insert is successful. print it.
}
return 0;
}

Resources