I created a program for bubble sort. It ends up in an infinite loop.
I have included comments at places so that the code is easily understandable.
Any suggestions on how to make the code smaller are welcome.
I was debugging the program and found this -
When stdin was "ccbbaa" and after some recursions when finally input(aabbcc) and temp(aabbcc) were same, then after the condition of strcmp() was executed, the value of 'temp' was changed to "baabcc".
Any reasons as to why this happened? — This is the reason for the infinite loop.
Does a character array have a '\0' at the end (while copying input to temp)?
I solved the problem by using a for loop instead of strcmp(). Investigating why strcmp() doesn't work currently.
Updated code is available - http://ideone.com/4Bdblh ( solved )
Buggy code
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<ctype.h>
void sort(char* input)
{
const int length = strlen(input);
int j = length -1;
char temp[length];
for(int i=0; i<length; i++)
{
temp[i]= *(input+i);
}
while(j)
{
if((int)*(input+1) < (int)*(input))
{
char temp1;
temp1 = *(input);
*input = *(input + 1);
*(input + 1) = temp1;
}
input++;
j--;
}
input = input - length +1;
while(strcmp(temp,input))
{
sort(input);
}
}
int main()
{
char* input = malloc(sizeof(char)*1000);
scanf("%[^\n]%*c",input);
sort(input);
printf("%s",input);
return 0;
}
Answer using arrays and for loops-
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<ctype.h>
#define MAX 1000
void sort(char input[])
{
const int length = strlen(input);
int j = length -1;
char temp[length];
for(int i=0; i<length; i++)
{
temp[i]= input[i];
}
int l=0;
while(j)
{
if(input[l+1] < input[l])
{
char temp1;
temp1 = input[l];
input[l] = input[l+1];
input[l+1] = temp1;
}
l++;
j--;
}
for(int k=0; k<length; k++)
{
if(temp[k]!=input[k])
{
sort(input);
}
}
}
int main()
{
char input[MAX];
scanf("%[^\n]%*c",input);
sort(input);
printf("%s",input);
return 0;
}
In C a string is just a char array ending in 0.
All string functions assume char arrays end with zero.
strcpy copies the string including the 0 delimiter at the end. Therefore, destination must have enough space for the string plus the zero.
strlen returns the length of the string, so the destination must be at least strlen (input)+1 long.
If you copy the string in a loop, then you mustn't forget to add the ending zero.
What I don't really get is why to make it recursive and doing a string comparison to detect completion. You can just implement two nested loops from 0 to length - 2. It's warranted it'll be sorted in the end.
If you want to make it adaptive, just store the last position you swapped. You needn't go further the next loop.
When stdin was "ccbbaa" and after some recursions when finally input(aabbcc) and temp(aabbcc) were same, then after the condition of strcmp() was executed, the value of 'temp' was changed to "baabcc".
Any reasons as to why this happened? — This is the reason for the infinite loop.
It just looked like the value of 'temp' was changed to "baabcc" because the function returned to the previous recursion level where the local temp had the same value as before. The main reason for the infinite loop is that due to the while(strcmp(temp,input)) the old, unsorted temp is compared again and again.
Does a character array have a '\0' at the end (while copying input to temp)?
The temp array in the buggy code hasn't; you could have written
char temp[length+1];
strcpy(temp, input);
or just used strncmp() rather than strcmp().
So, for the program to work it is sufficient to change
while(strcmp(temp,input))
to
if (strncmp(temp, input, length))
Related
#include <Stdio.h>
#include <string.h>
int main(){
char str[51];
int k = 1;
printf("Enter string\n");
scanf("%s", &str);
for(int i = 0; i < strlen(str); i++){
while(str[k] != '\0')){
if(str[i] == str[k]){
printf("%c", str[i]);
k++;
}
}
}
return 0;
}
It is simple C code that checks for duplicate characters in string and prints the characters. I am not understanding why it is producing an infinite loop. The inner while loop should stop when str[k] reaches the null terminator but the program continues infinitely.
Points to know
You don't need to pass the address of the variable str to scanf()
Don't use "%s", use "%<WIDTH>s", to avoid buffer-overflow
Always check whether scanf() conversion was successful or not, by checking its return value
Always use size_t to iterator over any array
i < strlen(str), makes the loop's time complexity O(n3), instead of O(n2), which also isn't very good you should check whether str[i] != 0. But, many modern compilers of C will optimize it by the way.
#include <Stdio.h> it is very wrong, stdio.h != Stdio.h
Call to printf() can be optimized using puts() and putc() without any special formatting, here also modern compiler can optimize it
while(str[k] != '\0')){ has a bracket (')')
Initialize your variable str using {}, this will assign 0 to all the elements of str
Better Implementation
My implementation for this problem is that create a list of character (256 max) with 0 initialized, and then add 1 to ASCII value of the character (from str) in that list. After that print those character whose value was greater than 1.
Time Complexity = O(n), where n is the length of the string
Space Complexity = O(NO_OF_CHARACTERS), where NO_OF_CHARACTERS is 256
Final Code
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
static void print_dup(const char *str)
{
size_t *count = calloc(1 << CHAR_BIT, sizeof(size_t));
for(size_t i = 0; str[i]; i++)
{
count[(unsigned char)str[i]]++;
}
for (size_t i = 0; i < (1 << CHAR_BIT); i++)
{
if(count[i] > 1)
{
printf("`%c`, count = %zu\n", i, count[i]);
}
}
free(count);
}
int main(void) {
char str[51] = {};
puts("Enter string:");
if (scanf("%50s", str) != 1)
{
perror("bad input");
return EXIT_FAILURE;
}
print_dup(str);
return EXIT_SUCCESS;
}
Read your code in English: You only increment variable k if character at index k is equal to character at index i. For any string that has different first two characters you will encounter infinite loop: char at index i==0 is not equal to char at index k==1, so k is not incremented and while(str[k]!=0) loops forever.
This seemed like a simple idea when I decided to try it out, but know it's driving me nuts.
I can reverse a whole string, but now I'm trying to reverse individual parts of a string.
Example:
"pizza is amazing" to "azzip si amazing"
Basically my program should reverse a string from point a to b, treating any words within it separately. My logic appears right (at least to me), but obviously something is wrong because my output is just the first word "pizza".
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *reverse(char *a, int i, int j){ //reverse the words
char temp;
while(i<j){
temp = a[i];
a[i] = a[j];
a[j] = temp;
i++;
j--;
}
return a;
}
char *words(char *a, int i, int j){ // identify if there are any words from a-b
int count = i;
while(i<j){
if(a[i] == ' '){ // a space signifies the end of a word
reverse(a , i-count, i);
count = 0; //reset count for next word
}
i++;
count++;
}
return a;
}
int main(){
char a[50];
char *a2;
printf("Enter a string:\n); //string input
scanf("%s", a);
int strlength = strlen(a) + 1;
a2 = (char *)malloc(strlength*sizeof(char));
strcpy( a2, a);
printf("Reversed string:\n%s", words(a, 0, 4)); // create a-b range
return 0;
}
I realize my problem is most likely within words(). I am out of ideas.
Problem 1:
You should be more careful naming variables, understandable and meaningful names help the programmer and others reading your code. Keep in mind this is extremely important.
Problem 2:
When you pass the parameter %s to scanf(), it will read subsequent characters until a whitespace is found (whitespace characters are considered to be blank, newline and tab).
You can use scanf("%[^\n]", a) to read all characters until a newline is found.
For further reference on scanf(), take a look here.
Problem 3:
Take a look at the words() function, you're not storing a base index (from where to start reversing). The call to reverse() is telling it to reverse a single character (nothing changes).
You didn't specified if a whole word must be inside the range in order to be reversed or even if it is on the edge (ex: half in, half out). I'll assume the whole word must be inside the range, check out this modified version of the words() function:
char *words(char *str, int fromIndex, int toIndex){
int i = fromIndex;
int wordStartingIndex = fromIndex;
/*
It is necessary to expand the final index by one in order
get words bounded by the specified range. (ex: pizza (0, 4)).
*/
toIndex += 1;
/* Loop through the string. */
while(i <= toIndex){
if(str[i] == ' ' || str[i] == '\0' || str[i] == '\n'){
reverse(str, wordStartingIndex, i-1);
wordStartingIndex = (i + 1);
}
i++;
}
return str;
}
This should get you started. The function it is not perfect, you'll need to modify it in order to handle some special cases, such as the one I've mentioned.
I'm trying to write a C program which eats a string of a priori bounded length and returns 1 if it's a palindrome and 0 otherwise. We may assume the input consists of lower case letters.
This is a part of a first course in programming, so I have no experience.
Here's my attempt. As soon as I try to build/run it on CodeBlocks, the program shuts down. It's a shame because I thought I did pretty well.
#include <stdio.h>
#define MaxLength 50
int palindrome(char *a,int size) /* checks if palindrome or not */
{
int c=0;
for(int i=0;i<size/2;i++) /* for every spot up to the middle */
{
if (*(a+i)!=*(a+size-i-1)) /* the palindrome symmetry condition */
{
c++;
}
}
if (c==0)
{
return 1; /*is palindrome*/
}
else
return 0; /*is not palindrome*/
}
int main()
{
char A[MaxLength]; /*array to contain the string*/
char *a=&A[0]; /*pointer to the array*/
int i=0; /*will count the length of the string*/
int temp;
while ((temp=getchar())!='\n' && temp != EOF) /*loop to read input into the array*/
{
A[i]=temp;
i++;
}
if (palindrome(a,i)==1)
printf("1");
else
printf("0");
return 0;
}
Remark. I'm going to sleep now, so I will not be responsive for a few hours.
Your approach is ok, though you have a number of small errors. First,#define MaxLength=50 should be #define MaxLength 50 (the text to replace, space, then its replacement).
You should also provide a prototype for your palindrome() function before main():
int palindrome(char *a,int size);
...or just move the whole palindrome() function above main(). Either a prototype or the actual function definition should appear before any calls to the function happen.
Next issue is that you're looking for a null character at the end of the input string. C strings are usually null terminated, but the lines coming from the console aren't (if there's a terminator it would be added by your program when it decides to end the string) -- you should probably check for a newline instead (and ideally, for errors as well). So instead of
while ((temp=getchar())!='\0')
try
while ((temp=getchar())!='\n' && temp != EOF)
When you print your results in main(), you should have a newline at the end, eg. printf("1\n"); instead of printf("1");, to ensure the output buffer gets flushed so you can see the output as well as to end that output line.
Then in your palindrome() function, your for loop sytax is wrong -- the three parts should be separated with semicolons, not commas. So change:
for(int i=0,i<size/2,i++)
...to:
for(int i=0; i<size/2; i++)
You also have an extra closing brace for the loop body to remove.
After fixing all that, it seems to work...
This directive
#define MaxLength=50
is invalid. There should be
#define MaxLength 50
Change the loop in main the following way
int temp;
^^^
while ( i < MaxLength && ( temp = getchar () )!= EOF && temp != '\n' )
{
A[i] = temp;
i++;
}
Otherwise if to use the original loop you have to place the zero into the buffer directly using the alt key and the numeric keypad.
The function itself can be written simpler
int palindrome( const char *a, int size) /* checks if palindrome or not */
{
int i = 0;
while ( i < size / 2 && *( a + i ) == *( a + size - i - 1 ) ) ++i; {
return i == size / 2;
}
Hi I am still new to c and have been working on this word sort program for some time now. the guidelines are:
Write a program that sorts a series of words entered by the user. Assume that each word is no more than 20 characters long. Stop reading when the user enters an empty word. Store each word in a dynamically allocated string, using an array of pointers (use the read_line function). After all lines have been read sort the array. Then use a loop to print the words in sorted order.
The problem I seem to be having is that the program will accept words but when I enter the empty word it goes to a new line and nothing happens. An help or advice would be greatly appreciated. here is my code so far.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LEN 20
#define LIM 20
int read_line(char str[], int n);
void sort_str(char *list[], int n);
int alpha_first(char *list[], int min_sub, int max_sub);
int main(void)
{
char *list[LIM];
char *alpha[LIM];
char word_str[LEN];
int word, i, j, num_count = 0;
for(;;){
printf("Enter a word: ");
scanf("%s", &word);
if(word == NULL)
break;
else
read_line(word_str, LEN);
list[i] = malloc(strlen(word_str) + 1);
strcpy(list[i], word_str);
alpha[i] = list[i];
}
sort_str(alpha, i);
for(i = 0; i < num_count; ++i){
printf("Sorted: ");
puts(list[i]);
}
return (0);
}
int read_line(char str[], int n)
{
int ch, i = 0;
while ((ch = getchar()) != '\n')
if (i < n)
str[i++] = ch;
str[i] = '\0';
return i;
}
void sort_str(char *list[], int n)
{
int i, index_of_min;
char *temp;
for (i= 0; i < n - 1; ++i) {
index_of_min = alpha_first(list, i, n - 1);
if (index_of_min != i) {
temp = list[index_of_min];
list[index_of_min] = list[i];
list[i] = temp;
}
}
}
int alpha_first(char *list[], int min_sub, int max_sub){
int i, first;
first = min_sub;
for(i = min_sub + 1; i <= max_sub; ++i){
if(strcmp(list[i], list[first]) < 0){
first = i;
}
}
return (first);
}
Your logic flow is flawed. If a word is entered, the scanf() will eat it from stdin and store a null-terminated string at the address of the integer 'word'. Any more than 3/7 chars entered, (32/64 bit, allowing for the null terminator), will start corrupting the stack. read_line() will then only have the line terminator to read from stdin, (assuming the UB doesn't blow it up first).
The problem I seem to be having is that the program will accept words but when I enter the empty word it goes to a new line and nothing happens.
There are several problems with this:
char word_str[LEN];
int word, i, j, num_count = 0;
/* ... */
scanf("%s", &word);
if(word == NULL)
break;
First, scanf("%s", &word) scans whitespace-delimited strings, and to that end it skips leading whitespace, including newlines. You cannot read an "empty word" that way, though you can fail to read a word at all if the end of the input is reached (or an I/O error occurs) before any non-whitespace characters are scanned.
Second, you are passing an inappropriate pointer to scanf(). You should pass a pointer to a character array, but you instead pass a pointer to an int. It looks like maybe you wanted to scan into word_str instead of into word.
Third, your scanf() format does not protect against buffer overflow. You should provide a field width to limit how many characters can be scanned. Moreover, you need to be sure to leave room for a string terminator.
Fourth, you do not check the return value of scanf(). If it fails to match any characters to the field, then it will not store any. Since it returns the number of fields that were successfully scanned (or an error indicator), you can detect this condition.
One way to correct the scanf() and "empty word" test would be:
int result;
result = scanf("%*[ \t]%19[^ \t\n]", word_str);
if (result < 1) break;
(That assumes a fixed maximum word length of 19 to go with your declared array length of 20.) You have several additional problems in your larger code, large among them that read_line() attempts to read the same data you just read via scanf() (in fact, that function looks altogether pointless). Also, you never update num_count, and after calling sort_str() you lose track of the number of strings you've read by assigning a new value to variable i.
There may be other problems, too.
In this program i'm trying to invert a string using 2 arrays:
The problem here is the program keeps writing the character "P" as the only output and i can't seem to figure out how to solve this.
#include<stdio.h>
#include<string.h>
#define TAM 256
int get_string(char string[TAM]);
int invert_string(char string[TAM]);
int string_out(char string[TAM]);
int main(){
char string[TAM]={0}; // always initialize a string to be completely zero, or unexpected behaviour may occur
get_string(string);
invert_string(string);
return 0;
}
int get_string(char string[TAM]){
printf("Enter a string: ");
scanf("%s",string);
return 0;
}
int invert_string(char string[TAM]){
char temporary_string[TAM]={0};
int i,j;
for(i=TAM,j=0;i>=0;i--){
if(string[i]== ' '){
continue;
}else{
temporary_string[j] = string[i];
j++;
}
}
printf("debug : temp string is : %s",temporary_string);
return 0;
}
int string_out(char string[TAM]){
printf("%s",string);
return 0;
}
Try this code in invert_string function:
int i,j;
for(i=strlen(string)-1,j=0;i>=0;i--){ // u can take variable and save length or directly pass length
if(string[i]== ' '){
continue;
}else{
temporary_string[j++] = string[i];
}
}
temporary_string[j] = '\0'; //Make last index NULL
printf("%s",temporary_string);
For an array declaration / definition of arr[256], the last element is arr[255].
In your for() loop,
for(i=TAM,j=0;i>=0;i--)
you're accessing arr[256] [267th element, considering index starts from 0] which is out-of-bound access and hence produces undefined behavior.
Then, the terminating NULL in the source array should be taken care of separately.
You need to have something like
if((string[i]== ' ') || (string[i]== '\0')){//....
Otherwise, the terminating NULL will become the first vaild element in the destination array, thus will end up printing nothing.
Lastly, don't forget to NULL terminate the new array.
temporary_string[j] = '\0';
Note: Once you'vre fixed this version of code, think of some optimization.
Check the below code.
#include<stdio.h>
#include<string.h>
#define TAM 256
int get_string(char string[TAM]);
int invert_string(char string[TAM]);
int string_out(char string[TAM]);
int main(){
char string[TAM]={0}; // always initialize a string to be completely zero, or unexpected behaviour may occur
get_string(string);
invert_string(string);
return 0;
}
int get_string(char string[TAM]){
printf("Enter a string: ");
scanf("%s",string);
return 0;
}
int invert_string(char string[TAM]){
char temporary_string[TAM]={0};
int i,j;
for(i=TAM-1,j=0;i>=0;i--){
if((string[i]== ' ') || (string[i]== '\0')){
continue;
}else{
temporary_string[j] = string[i];
j++;
}
}
temporary_string[j] = '\0';
printf("debug : temp string is : %s\n",temporary_string);
return 0;
}
Make you loop condition starting with 255.
for ( i=TAM-1 ; j=0; i>=0 ; i--)
...
256 is array out of bounds.
There are lot of issues with your code. At first you cannot start with 256 as i mentioned in the comment. Again you don't know how much is the length of the source string. Even if u have taken the size to be 256 the string inputted from the terminal can be of length smaller than 256. So first you must know what is the size of the string inputted from the terminal. After that start with strlen(string) - 1 and copy until i becomes 0. Then do temporary_string[strlen(string)-1]='\0'