end of line character is not detected - c

A simple program, a static string which is used to read the input, then pass it to the function. Just wondering why it can not find the '\0' character using the while(*string!='\0') expression.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int is_palindrome(char *string)
{
int length, mid, end, i;
length=0;
if (string == NULL)
return 0;
while (string[length] != '\0')
{
printf("%c\n", string[length]);
length++;
}
//Not working version
/*
while(*string!='\0')
length++;
*/
end = length - 1;
mid = length / 2;
printf(" end=%d, mid=%d\n", end, mid);
for (i = 0; i < mid; i++) {
if (string[i] != string[end]) {
printf("It's not palindrome\n");
return 0;
}
end--;
}
if (i == mid) {
printf("It's palindrome\n");
return 1;
}
return 0;
}
int main(void)
{
char string[100];
printf("Enter a string to test for the parlindrome\n");
gets(string);
int length = strlen(string);
printf("You entered %s,length is %d\n", string, length);
if (is_palindrome(string))
;
printf("Enter to Quit\n");
char x;
scanf("%c", &x);
return 0;
}

Instead of
while(*string!='\0')
length++;
write
char* p = string;
while( *p++ )
length++;
otherwise the pointer will not move and you become stuck in an infinite loop (if the string is not empty). Use p to avoid changing the original pointer.
Also initialize all variables before using them, good rule of thumb.

Initialize length to 0 before using its value in the while loop.
Or you could use the standard library function strlen().
Also, in the palindrome check, you should probably decrease end at the same you increase i. As it is, you're comparing the characters in the first half each with the same char at the end. This will match strings like "aaaabfa" but not "abcdcba".

Related

Error when extracting sub-string from the start of source string in C

This is from an exercise in Chapter 9 of Programming in C 4th Edition. The programme is to read in characters into a string and extract a portion of the string into a sub-string by specifying a start position and number of characters.
The programme compiles and runs well except when the zeroth position of the source is stated as the start. Nothing is then displayed.
This is my code.
/* Programme to extract a portion from a string using function
sub-string (source, start, count, result) ex9.4.c
ALGORITHM
Get text input into a char array (declare to be fixed size);
Determine length of source string;
Prepare result array to be dynamic length using desired count + 1;
Copy from source array into result array
*/
#include <stdio.h>
#include <stdbool.h>
#define MAX 501
void read_Line (char buffer[]);
int string_Length (char string[]);
void sub_String (char source[], int start, int count, char result[]);
int main(void)
{
char strSource[MAX];
bool end_Of_Text = false;
int strCount = 0;
printf("This is a programme to extract a sub-string from a source string.\n");
printf("\nType in your text (up to 500 characters).\n");
printf("When you are done, press 'RETURN or ENTER'.\n\n");
while (! end_Of_Text)
{
read_Line(strSource);
if (strSource[0] == '\0')
{
end_Of_Text = true;
}
else
{
strCount += string_Length(strSource);
}
}
// Declare variables to store sub-string parameters
int subStart, subCount;
char subResult[MAX];
printf("Enter start position for sub-string: ");
scanf(" %i", &subStart);
getchar();
printf("Enter number of characters to extract: ");
scanf(" %i", &subCount);
getchar();
// Call sub-string function
sub_String(strSource, subStart, subCount, subResult);
return 0;
}
// Function to get text input
void read_Line (char buffer[])
{
char character;
int i = 0;
do
{
character = getchar();
buffer[i] = character;
++i;
}
while (character != '\n');
buffer[i - 1] = '\0';
}
// Function to count determine the length of a string
int string_Length (char string[])
{
int len = 0;
while (string[len] != '\0')
{
++len;
}
return len;
}
// Function to extract substring
void sub_String (char source[], int start, int count, char result[])
{
int i, j, k;
k = start + count;
for (i = start, j = 0; i < k || i == '\0'; ++i, ++j)
{
result[j] = source[i];
}
result[k] = '\0';
printf("%s\n", result);
}
I am using Code::Blocks on Linux Mint.
Being someone that just started learning programming recently with CS50 and 'Programming in C' books, I did not know how to setup the debugger in Code::Blocks. But thanks to the push by #paulsm4, I managed to get the debugger working. Using the watches window of the debugger, I could see that the while loop in the main function was overwriting the first character in the source array with a null character. The fix was to add a break statement. Thanks to #WhozCraig and #Pascal Getreuer for pointing out other errors that I had missed. This is the corrected code now:
/* Programme to extract a portion from a string using function
sub-string (source, start, count, result) ex9.4.c
ALGORITHM
Get text input into a char array (declare to be fixed size);
Determine length of source string;
Prepare result array to be dynamic length using desired count + 1;
Copy from source array into result array
*/
#include <stdio.h>
#include <stdbool.h>
#define MAX 501
void read_Line (char buffer[]);
int string_Length (char string[]);
void sub_String (char source[], int start, int count, char result[]);
int main(void)
{
char strSource[MAX];
bool end_Of_Text = false;
int strCount = 0;
printf("This is a programme to extract a sub-string from a source string.\n");
printf("\nType in your text (up to 500 characters).\n");
printf("When you are done, press 'RETURN or ENTER'.\n\n");
while (! end_Of_Text)
{
read_Line(strSource);
if (strSource[0] == '\0')
{
end_Of_Text = true;
}
else
{
strCount += string_Length(strSource);
}
break;
}
// Declare variables to store sub-string parameters
int subStart, subCount;
char subResult[MAX];
printf("Enter start position for sub-string: ");
scanf(" %i", &subStart);
getchar();
printf("Enter number of characters to extract: ");
scanf(" %i", &subCount);
getchar();
// Call sub-string function
sub_String(strSource, subStart, subCount, subResult);
return 0;
}
// Function to get text input
void read_Line (char buffer[])
{
char character;
int i = 0;
do
{
character = getchar();
buffer[i] = character;
++i;
}
while (character != '\n');
buffer[i - 1] = '\0';
}
// Function to count determine the length of a string
int string_Length (char string[])
{
int len = 0;
while (string[len] != '\0')
{
++len;
}
return len;
}
// Function to extract substring
void sub_String (char source[], int start, int count, char result[])
{
int i, j, k;
k = start + count;
// Source[i] == '\0' is used in case count exceeds source string length
for (i = start, j = 0; i < k || source[i] == '\0'; ++i, ++j)
{
result[j] = source[i];
}
result[j] = '\0';
printf("%s\n", result);
}

comparing a char to a string in C

I'm quite new to C and I'm wondering why in the code below, the char I'm comparing to each letter of the string word is showing that it's equal everytime.
For example
If I've inputted the word
apple
and I'm looking for any repeating char in "apple" my function. I pass in to the function each char of apple such as a, p, p etc. It should return 1 when I pass in p since it's repeated, but instead, for every char of apple, my function says a == word[0], a == word[1] even though word[1] for "apple" is 'p'.
I know char is ASCII, so each char has a number value, but I'm not sure why this is not working. Perhaps, I'm using the pointer *word in the functions arguments incorrectly?
My code is below for my function, rpt_letter:
int rpt_letter(char *word, char c)
{
int i;
int count = 0;
i = 0;
printf("This is the WORD %s\n", word);
while(count < 2)
{
if(word[i] == c)
{
count++;
printf("the count is %d\n the char is %c and the string is %c\n", count, c, word[i]);
}
i++;
}
if (count<2)
{
// printf("letter %c was not found in the array. \n", c);
return 0;
}
else
{
//printf("letter %c was found at index %d in the array.\n", c, mid);
repeats[rpt_counter] = c;
rpt_counter++;
return 1;
}
return 0;
}
I'll include the main method just in case -- but I believe the main method is working well
int main(void)
{
//! showArray(list, cursors=[ia, ib, mid])
//int n = 51;
char word[51];
scanf("%s", word);
//length of string
for (n=0; word[n] != '\0'; n++); //calculate length of String
printf("Length of the string: %i\n", n);
int count = 0;
//sort words
int i;
char swap = ' ';
for(int k = 0; k < n; k++)
{
for (i=0; i<n-1; i++)
{
//if prev char bigger then next char
if (word[i] > word[i+1])
{
//make swap = prev char
swap = word[i];
//switch prev char with next char
word[i] = word[i+1];
//make next letter char
word[i+1] = swap;
}
}
}
printf("%s\n", word);
for (i=0; i<n-1; i++)
{
int rpt = rpt_letter(word, word[i]);
if(rpt == 1)
{
count++;
}
}
printf("%d", count);
return 0;
}
I've tried a number of things such as using the operator !=, also <, > but it gives me the same result that each word[ia] == c.
You are getting this issue because in your code rpt_letter() the while loop has a terminating condition count >= 2. Now consider input apple and character a. As a appears in apple only once, the count after traversing the whole word remains 1. But the loop doesn't terminate. So, the index i becomes greater than the length of string and tries to check the character appearing after that.
The loop terminates eventually when it gets another a this way. You need to add a check for the terminating null character in your loop so that it doesn't cross the length of the string .
Change the while loop condition to something like -
while((count < 2) && (word[i] != '\0'))

Keep getting runtime error for simple C program

I have to write a program that checks whether the string is a palindrome or not.
A palindrome is a sequence which is the same forwards as backwards.
For example, kayak is a palindrome, canoe is not a palindrome, hannah is a palindrome, etc.
Here is my code so far:
#include <stdio.h>
#include <string.h>
#define MAX_CHAR 4096
int main(void) {
printf("Enter a string: ");
char line[MAX_CHAR] = {0};
fgets(line, MAX_CHAR, stdin);
int length = strlen(line) - 1;
int i = 0;
int j = length - 1;
char line2[length];
while (i < length){
if (j >= 0){
line2[i] = line[j];
}
i++;
j--;
}
if (strcmp(line, line2) != 0){
printf("String is not a palindrome\n");
} else if (strcmp(line, line2) == 0) {
printf("String is a palindrome\n");
}
return 0;
}
This works for non-palindromes but each time I test with a palindrome, I am getting a runtime error as shown in the image.
How do I solve this?
The issue you are facing is caused by the fact that you do not add a null terminator to line2 (and the array also doesn't have enough space for one), therefore line2 is not a null-terminated byte string.
Passing a pointer to anything other than a null-terminated byte string to strcmp invokes undefined behavior
The simplest way to fix your code is to make the following changes:
/* Don't subtract 1 from `strlen`, otherwise you don't copy the entire string in your loop */
int length = strlen(line);
/* Unchanged */
int i = 0;
int j = length - 1;
/* increase size of array by 1 to have space for null-terminator */
char line2[length + 1];
/* Loop is unchanged */
while (i < length){
if (j >= 0){
line2[i] = line[j];
}
i++;
j--;
}
/* Add null-terminator to have a valid byte string */
line2[length] = '\0';
Please also note that there are simpler ways to achieve the palindrome check, but this answer only focuses on why your code runs into the runtime error.
EDIT: As pointed out in the comments fgets also stores the newline character inside the array. In order for your palindrome check to work correctly you need to adjust your code (e.g.: removing the newline from line before creating line2 and copying the characters)
Easier way:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int palindrome(const char *word)
{
size_t len = strlen(word);
const char *end = word + len -1;
len >>= 1;
while(len--)
{
if(*word++ != *end--)
return 1; //not
}
return 0; //yes;
}
int main()
{
printf("%s\n", palindrome("kayak") ? "No" : "Yes");
}
You have wrong bounds checking, and also fgets reads newline which you have to delete. This is the only compete answer which also check if string entered is not empty:
#include <string.h>
#define MAX_CHAR 4096
int main(void) {
printf("Enter a string: ");
char line[MAX_CHAR] = {0};
fgets(line, MAX_CHAR, stdin);
//remove new line
int length = strlen(line);
if (length > 0) {
line[length-1] = '\0';
}
//update length
length = strlen(line);
if (!length) {
printf("String is empty\n");
return 1;
}
int i = 0;
int j = length - 1;
char line2[length+1];
while (i < length){
line2[i++] = line[j--];
}
//Add 0 char
line2[i] = '\0';
if (strcmp(line, line2) != 0){
printf("String is not a palindrome\n");
} else if (strcmp(line, line2) == 0) {
printf("String is a palindrome\n");
}
return 0;
}

reverse-alphabetizing a string in c

#include <stdio.h>
#include <string.h>
int main(void)
{
int i, temp;
char input[50];
printf("Enter a string: \n");
scanf("%s", input);
for(i=0; input[i] != '\0'; i++) {
if(strcmp(input[i], input[i+1])<0) {
temp=input[i];
input[i]=input[i+1];
input[i+1]=temp;
}
}
printf("%s\n", input);
return(0);
}
I am supposed to write a program which sorts the characters of a user-inputted string into backwards alphabetical order. I believe I am using the strcmp function incorrectly?
You are comparing chars, you dont need to use strcmp which compares null terminated char arrays.
a simple input[i] == input[i+1] will be OK.
this will compare the ascii codes of the characters.
strcmp is used to compare char arrays not chars themselves, which can be simply compared with >.
That's not the only problem: bubble sort needs 2 loops (O(n**2) complexity) so even with the compare fix, your loop doesn't sort it completely. For instance, enter acbac, one loop will not be enough to move the last c in 2nd position since it only swaps neighbour elements once.
Here's an implementation which does the job, using a double loop (with half of the string in the inner loop) and proper char comparison.
#include <stdio.h>
#include <string.h>
int main(void)
{
int i,j, temp;
char input[50];
printf("Enter a string: \n");
scanf("%49s", input);
for(i=0; input[i] != '\0'; i++) {
for(j=i+1; input[j] != '\0'; j++) {
if (input[i] < input[j]) {
temp=input[i];
input[i]=input[j];
input[j]=temp;
}
}
}
printf("%s\n", input);
return(0);
}
Why not use qsort?
int compareFunction(const void *a, const void *b) {
char char1 = 0[(char *) a];
char char2 = 0[(char *) b];
if (char1 > char2) return -1;
if (char1 == char2) return 0;
if (char1 < char2) return 1;
}
....
qsort(input, strlen(input), 1, compareFunction);

How to compare an array to a reversed one and check if their values match?

I wrote a program that reverses an array with the strrev() function and checks if its values matches the original one, sort of a palindrome. When the values match, it prints Palindrome, else, Not a palindrome.
But when I compare them, and the values don't match, it still prints Palindrome.
Here is the code:
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
#include <string.h>
#define MAX_LEN 100
void palindrom(char string[]);
int main()
{
char string[MAX_LEN] = { 0 };
printf("Enter string (max length 100 chars): ");
fgets(string, MAX_LEN, stdin);
if(string[strlen(string)-1] == '\n') { string[strlen(string)-1] = 0; }
palindrom(string);
return (0);
}
void palindrom(char string[])
{
int check = 0;
check = strcmp(strrev(string), string);
if (check == 0)
{
printf("Palindrome");
}
else
{
printf("Not a palindrome");
}
}
What's my problem? Thanks.
From what I can tell strrev may modify the original string as well, so you need to copy it.
The key is strrev.
Here's a program in C that will do what you're testing for:
#include <stdio.h>
#include <string.h>
int main()
{
char a[100], b[100];
printf("Enter the string to check if it is a palindrome\n");
fgets(a, 100, stdin);
strcpy(b,a);
strrev(b);
if (strcmp(a,b) == 0)
printf("Entered string is a palindrome.\n");
else
printf("Entered string is not a palindrome.\n");
return 0;
}
Since others have clarified what the problem is, I would like to point that it would be faster to check if s[0] == s[len-1], s[1] == s[len-2], until half (rounded up) of the string has been checked.
This would require no extra memory, no copy and half as many comparisons.
Something along the lines of:
void palindrom(char string[])
{
int len = strlen(string) - 1;
int i, limit = len/2 + (len % 2);
for (i = 0; i < limit; i++){
if (string[i] != string[len-i]){
printf("Not a palindrome\n");
return;
}
}
printf("Palindrome\n");
}
Your function fails because strrev modifies the string. You effectively always compare the reversed string to itself.
Here is an alternate function that does not modify the string:
void palindrom(const char *str) {
for (size_t i = 0, j = strlen(str); i < j; i++, j--) {
if (str[i] != str[j - 1]) {
printf("Not a palindrome\n");
return;
}
}
printf("Palindrome\n");
}
You don't need to use strrev to test for a palindrome the following function detects a palindrome just fine without using non-standard C functions:
int ispalindrome(char *str, int len)
{
char *p = &str[0];
char *q = &str[len - 1];
do
{
if(p >= q)
{
return 1;
}
} while (*p++ == *q--);
return 0;
}

Resources