Making a program that implements functions that work with arrays - c

Doing an assignment where I have to implement some functions. One of those functions is to check if a string is a palindrome.
#include <stdio.h>
#include <stdlib.h>
char string[] = "cameron";
char string2[] = "mah";
char palindrome[] = "madam";
char notPalindrome[] = "music";
int removeChar(char *str1, char * str2, char c){
int length = 0;
for (int i = 0; str1[i] != '\0'; i++){
length++;
}
for (int i = 0; i <= length; i++){
if (str1[i] == c){
str2[i] = '*';
}
else {
str2[i] = str1[i];
}
}
for (int i = 0; i<= length; i++){
printf("%c", str2[i]);
}
}
int isPalindrome(char *str){
int length = 0;
for (int i = 0; str[i] != '\0'; i++){
length++;
}
int j = length - 1;
int reversible = 0;
for (int i = 0; i < j; i++){
if (str[i] != str[j]){
reversible++;
break;
}
j--;
}
if (reversible > 0){
printf("\nString is not a palindrome\n");
}
else {
printf("\nString is replaceable\n");
}
}
int main(){
removeChar(string, string2, 'm');
isPalindrome(palindrome);
return 0;
}
When I run this code it says the string is not a palindrome when it should be, but why is it that if I change isPalindrome(palindrome); to isPalindrome("madam"); it works.
Also Why is it that if I comment out //removeChar(string, string2, 'm');, isPalindrome() will work properly.

You have a buffer overflow. removeChar implicitly assumes that str2 is the same length as str1. So when you run this:
for (int i = 0; i <= length; i++){
if (str1[i] == c){
str2[i] = '*';
}
else {
str2[i] = str1[i];
}
}
with str1 being "cameron" and str2 being "mah", you go past the boundaries of str2 and into the memory where palindrome is stored. So after you run removeChar(string, string2, 'm');, the char[] that used to hold mah\0 now holds ca*e and the char[] that used to hold madam\0 now holds ron\0m\0. Obviously, "ron" is not a palindrome. Try printing the values of your strings after removeChar(string, string2, 'm'); and you should see this in action.
The only reason you're allowed to do this at all without a segmentation fault is because you're using char[] instead of char*, by the way. You might prefer to use pointers over arrays so things like this don't fail silently.

Related

Function with two parameters removes all spaces from string

I'm learning C and I've a problem with this school homework.
I have to make function which get two strings from user as parameters. The function removes all spaces from the first string and returns the "cleaned" strings as the other parameter.
The main function ask three strings, uses function to remove spaces and prints "cleaned" strings.
My code doesn't work as it should? What goes wrong?
#include <stdio.h>
void removeSpaces(char *, char *);
int main(){
int i, j;
char string[101], strings[1][101];
for(i = 0; i <= 2; i++){
fgets(string, 100, stdin);
for(j = 0; string[j] != '\0'; j++){
strings[i][j] = string[j];
}
strings[i][j] = '\0';
removeSpaces(strings[i], strings[i]);
}
for(i = 0; i <= 0; i++){
for(j = 0; j <= 101; j++){
printf("%c", strings[i][j]);
}
}
}
void removeSpaces(char *string1, char *string2){
int i, j;
for(i = 0; string1[i] != '\0'; i++){
if(string1[i] != ' '){
string2[i] = string1[j];
j++;
}
}
string2[i] = '\0';
}
You have to be more careful when writing code. There are several things wrong:
In removeSpaces(), you never initialize j. So it can be anything.
You are also mixing up i and j inside removeSpaces(). i should only be used to index string1, and j only for string2.
strings[1][101] is only one string, not 3. But the first for-loop in main() runs 3 times.
You don't have to print strings character by character, just printf("%s", strings[i]) or fputs(strings[i], stdout).
I'm not sure why you used a two-dimensional array strings here. You only need two strings. Renaming the variables can also help you avoid getting confused. Consider:
#include <stdio.h>
static void removeSpaces(const char *input, char *output) {
int i, o;
for(i = 0, o = 0; input[i] != '\0'; i++) {
if(input[i] != ' ') {
output[o] = input[i];
o++;
}
}
output[o] = '\0';
}
int main() {
char input[100], output[100];
fgets(input, sizeof input, stdin);
removeSpaces(input, output);
fputs(output, stdout);
}

Selection of unique characters

Please, help with the code.
Requirement:
Write a function my_union that takes two strings and returns, without doubles, the characters that appear in either one of the strings.
Example:
Input: "zpadinton" && "paqefwtdjetyiytjneytjoeyjnejeyj"
Output: "zpadintoqefwjy"
My code:
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
char *my_union(char *a, char *b) {
char *str;
// Algorithm for excluding nonunique characters from string a(given in
// parameters).
str[0] = a[0];
int k = 1;
str[k] = '\0';
for (int i = 1; a[i] != '\0'; i++) {
bool is = true;
for (int j = 0; str[j] != '\0'; j++) {
if (str[j] == a[i]) {
is = false;
break;
}
}
if (is) {
str[k] = a[i];
k++;
str[k] = '\0';
}
} // In this case we are excluding excess character 'n' from "zpadinton", so
// str is equal to "zpadinto".
// Algorithm for adding unique characters from array b(given in parameters)
// into str.
for (int i = 0; b[i] != '\0'; i++) {
bool is = true;
for (int j = 0; str[j] != '\0'; j++) {
if (str[j] == b[i]) {
is = false;
break;
}
}
if (is) {
strncat(str, &b[i], 1);
}
}
return str;
}
The first algorithm is almost identical with second, but it doesn't work(. Mb I messed up with memory, give some advice, pls.
If you mean, get the unique characters from two strings and store them into a new string, try this code ;
First, you must allocate a memory for str. In your code, str is not pointing allocated memory location, so you will probably get segmentation fault.
int contains(const char * str,char c)
{
for (int i = 0; i < strlen(str); ++i)
if(str[i] == c)
return 1;
return 0;
}
char * my_union(char *a, char*b)
{
char * res = (char*)malloc(sizeof(char)*(strlen(a) + strlen(b)));
int pushed = 0;
for (int i = 0; i < strlen(a); ++i)
{
if(!contains(res,a[i])){
res[pushed] = a[i];
pushed++;
}
}
for (int i = 0; i < strlen(b); ++i)
{
if(!contains(res,b[i])){
res[pushed] = b[i];
pushed++;
}
}
return res;
}
int main(int argc, char const *argv[])
{
char string1[9] = "abcdefgh";
char string2[9] = "abegzygj";
char * result = my_union(string1,string2);
printf("%s\n", result);
return 0;
}
Also, do not forget the free the return value of my_union after you done with it.

Returning common chars

My code is supposed to compare 2 strings and returns the common characters in alphabetical order. If there are no common chars, it will return a null string.
However the program is not running.
Code
void strIntersect(char *str1, char *str2, char *str3)
{
int i,j, k;
i = 0;
j = 0;
k = 0;
while(str1[i]!='\0' || str2[j]!='\0')
{
if(strcmp(str1[i],str2[j])>0)
{
str3[k] = str1[i];
k++;
}
else if (strcmp(str2[j],str1[i])>0)
{
str3[k] = str2[j];
k++;
}
i++;
j++;
}
}
Example
Input string 1:abcde
Input string 2:dec
Output: cde
How do I get it to work?
There are quite a few problems with your code
strcmp is not needed for a simple char comparison
Is the 3rd char string allocated by the caller?
Your approach won't work if source strings are either of different sizes or are not alphabetical.
My solution assumes that input is ASCII, and is efficient (used a simple char array with indexes denoting ASCII value of the character).
If a character is found in str1, the char map will have a 1, if it is common, it will have a 2, otherwise, it will have a 0.
void strIntersect(char *str1, char *str2, char *str3)
{
int i=0, j=0, k=0;
char commonCharsMap[128] = { 0 };
while(str1[i] != '\0')
{
commonCharsMap[str1[i++]] = 1;
}
while(str2[j] != '\0')
{
if(commonCharsMap[str2[j]] == 1)
{
commonCharsMap[str2[j++]] = 2;
}
}
for(i=0; i<128; i++)
{
if(commonCharsMap[i] == 2)
{
str3[k++] = i;
}
}
str3[k++] = '\0';
}
int main()
{
char str1[] = "abcde";
char str2[] = "dce";
char str3[30];
strIntersect(str1, str2, str3);
printf("Common chars: %s\n", str3);
return 0;
}
A option is to iterate over the complete second string for each character in the first string
int i = 0;
int k = 0;
while(str1[i] != '\0') {
int j = 0;
while(str2[j] != '\0') {
if (str1[i] == str2[j]) {
str3[k] = str1[i];
k++;
}
j++;
}
i++;
}
I replaced the strcmp because you are comparing single characters not a string
Your if case and Else if case are identical and you are just comparing elements according to your Index. i.e you are comparing first element with first, second with second and so on. This won't provide you solution. I suggest use two for loops. I will provide you code later if you want

c- finding how many times a character occurs in a string

#include <stdio.h>
#include <string.h>
#define SIZE 40
int main(void)
{
char buffer1[SIZE] = "computer program";
char *ptr;
int ch = 'p', j = 0, i;
for (i = 0; i<strlen(buffer1); i++)
{
ptr = strchr(buffer1[i], ch);
if (ptr != 0) j++;
printf(" %d ", j);
}
}
I want to count how many times a character occurs in a string.
In my program I chose the character 'p'.
I know Pascal, I am learning C now. In pascal is a function called Pos(x,y) which is searching for x in y. Is something familiar to this? I think what I used here is not.
The function signature of strchr is
char *strchr(const char *s, int c);
You need to pass a char* but you have passed a char. This is wrong.
You have used the strlen in loop - making it inefficient. Just calculate the length of the string once and then iterate over it.
char *t = buffer;
while(t!= NULL)
{
t = strchr(t, ch);
if( t ) {
t++;
occurences++;
}
}
And without using standard library functions you can simply loop over the char array.
size_t len = strlen(buffer);
for(size_t i = 0; i < len; i++){
if( ch == buffer[i]) occurences++;
}
Or alternatively without using strlen
char *p = buffer;
while(*p){
if( *p == ch ){
occurences++;
}
p++;
}
Or
for(char *p = buffer; *p; occurences += *p++ == ch);
Try this example :
int main()
{
char buffer1[1000] = "computer program";
char ch = 'p';
int i, frequency = 0;
for(i = 0; buffer1[i] != '\0'; ++i)
{
if(ch == buffer1[i])
++frequency;
}
printf("Frequency of %c = %d", ch, frequency);
return 0;
}

Reverse Words in String

For some reason, I can't get this to work! Can anyone tell me where I've gone wrong? This is supposed to reverse the words in a give string (i.e from "this is a test" to "test a is this")
#include <stdio.h>
#include <stdlib.h>
char *reverse(char const *input)
{
char *ret = (char *)malloc(sizeof(char) * strlen(input));
int length = 0;
int numWords = 1;
int i;
for(i=0; input[i]!=NULL; i++)
{
length++;
if(input[i]==' ')
numWords++;
}
char words[numWords];
int currentWord = numWords;
for(i=0; input[i]!=NULL; i++)
{
if (input[i]==' '){
currentWord--;
}else{
words[currentWord] = words[currentWord] + input[i];
}
}
for(i=0; i < numWords; i++)
{
ret = ret + words[i];
}
return ret;
}
int main(int argc, char **argv)
{
int nTestcase = 0;
int i = 0;
char inputstr[100];
char *reversedStr = NULL;
scanf("%d\n", &nTestcase);
for (i = 0; i < nTestcase; i++)
{
fgets(inputstr, 100, stdin);
reversedStr = reverse(inputstr);
printf("%s\n", reversedStr);
free(reversedStr);
memset(inputstr, 0, 100);
}
return 0;
}
words[currentWord] = words[currentWord] + input[i];
You can't add characters to each other like that expecting string concatenation. And I imagine you expect words to be an array of words (i.e. strings), but its type is not that, words is just an array of characters.
Like #Tom said, you're doing this again in the last for loop:
ret = ret + words[i];
Joseph, unlike other programming languages ( c# or PHP ), string handling functions of C are quite basic.
You cannot add strings directly, however there are a host of library functions you can use to accomplish the same task.
Check out,
strtok - Use it to split the string to words. strtok reference
strncat - Use to concatenate strings
strings in C are just byte arrays terminated with the null character ( byte with value 0).
Here is shorter/cleaner way
private char[] reverseWords(char[] words) {
int j = words.length - 1;
for (int i = 0; i < (words.length)/2; i++) {
if(i==j)
continue;
char temp = words[i];
words[i] = words[j];
words[j]=temp;
j--;
}
int lastIndex = 0;
for (int i=0;i<words.length;i++){
if(words[i]==' '){
words = reverseWord(words,lastIndex,i-1);
lastIndex=i+1;
}
}
words = reverseWord(words,lastIndex,words.length-1);
return words;
}
private char[] reverseWord(char[] words, int from, int to) {
int j=to;
for(int i=from;i<((to/2)+from/2);i++){
if(i==j) continue;
char temp = words[j];
words[j]=words[i];
words[i]=temp;
j--;
}
return words;
}

Resources