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.
Related
As part of an assignment, I am supposed to write a small program that accepts an indefinite number of strings, and then print them out.
This program compiles (with the following warning
desafio1.c:24:16: warning: format not a string literal and no format arguments [-Wform
at-security]
printf(words[i]);
and it prints the following characters on the screen: �����8 ���#Rl�. I guess it did not end the strings I entered by using getchar properly with the null byte, and it prints out garbage. The logic of the program is to initiate a while loop, which runs untill I press the enter key \n, and if there are an space, this is a word that will be store in the array of characters words. Why am I running into problems, if in the else statement once a space is found, I close the word[i] = \0, in that way and store the result in the array words?
#include <stdio.h>
#include <string.h>
int main()
{
char words[100][100];
int i,c;
char word[1000];
while((c = getchar()) != '\n')
{
if (c != ' '){
word[i++] = c;
c = getchar();
}
else{
word[i] = '\0';
words[i] == word;
}
}
int num = sizeof(words) / sizeof(words[0]);
for (i = 0; i < num; i++){
printf(words[i]);
}
return 0;
}
Here are some fixes to your code. As a pointer (as mentioned in other comments), make sure to enable compiler warnings, which will help you find 90% of the issues you had. (gcc -Wall)
#include <stdio.h>
#include <string.h>
int main() {
char words[100][100];
int i = 0;
int j = 0;
int c;
char word[1000];
while((c = getchar()) != '\n') {
if (c != ' '){
word[i++] = c;
} else {
word[i] = '\0';
strcpy(words[j++], word);
i = 0;
}
}
word[i] = '\0';
strcpy(words[j++], word);
for (i = 0; i < j; i++) {
printf("%s\n", words[i]);
}
return 0;
}
i was uninitialized, so its value was undefined. It should start at 0. It also needs to be reset to 0 after each word so it starts at the beginning.
The second c = getchar() was unnecessary, as this is done in every iteration of the loop. This was causing your code to skip every other letter.
You need two counters, one for the place in the word, and one for the number of words read in. That's what j is.
== is for comparison, not assignment. Either way, strcpy() was needed here since you are filling out an array.
Rather than looping through all 100 elements of the array, just loop through the words that have actually been filled (up to j).
The last word input was ignored by your code, since it ends with a \n, not a . That's what the lines after the while are for.
When using printf(), the arguments should always be a format string ("%s"), followed by the arguments.
Of course, there are other things as well that I didn't fix (such as the disagreement between the 1000-character word and the 100-character words). If I were you, I'd think about what to do if the user entered, for some reason, more than 1000 characters in a word, or more than 100 words. Your logic will need to be modified in these cases to prevent illegal memory accesses (outside the bounds of the arrays).
As a reminder, this program does not accept an indefinite number of words, but only up to 100. You may need to rethink your solution as a result.
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;
}
For an assignment I am doing, I have to print out the initials from a string in C (or, an array of characters). To do this, I know that I need to find where the SPACE is, using (int)name[i] == 32 to find if the current character is a SPACE. My only issue with this is that I am having trouble figuring out how I can find the space, and then store the next character in the array of character. (e.g., user enters Mike Baggins, I have to print out MB). I will post my code below, to show you how far I've gotten. Please help, but please don't give me the full solution. Thank you!
#include <cs50.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
string name = get_string(); // gets the user's input
char firstI = name[0]; // stores the first character from the user's input
int len = strlen(name);
if((int)firstI >= 97 && (int)firstI <= 122) // checks if the character is lowercase
{
firstI -= 32; // makes the value uppercase
}
for(int i = 0; i < len; i++)
{
if((int)name[i] == 32) // checks if the character is SPACE
{
printf("I found a space!\n"); // prints out "I found a space"
}
}
printf("%c\n", firstI); // prints out the first initial
}
It's actually simple, see this for example
#include <stdio.h>
#include <ctype.h>
int
main(void)
{
char array[10];
char string[] = "Mike Baggins";
int j;
// Always put the first non-whitespace
// character (we should probably skip all
// spaces first
array[0] = string[0];
// Now start at the character following the first
j = 1;
for (int i = 1; ((string[i - 1] != '\0') && (j < sizeof(array) - 1)); ++i) {
if (string[i - 1] == ' ') {
array[j++] = toupper(string[i]);
}
}
array[j] = '\0';
puts(array);
return 0;
}
All I needed was to know that strings are simply arrays with a special value marking the end of them → '\0'. Of course, you can improve it a lot. For instance, you could count how many initials are there in the input string and allocate enough space to store them all.
Also, this will only work if the interesting character follows the space immediately, but knowing that it's just an array I am sure you can figure out how to extend it to make it ignore consecutive spaces.
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.
I have one 'simple' (I hope) question. I am actually coding some little program and I need to compare two strings, same length, but different letters like
Eagle
and
Hdjoh
I want to compare the first letter of the first string with the first letter of the second string,
the second letter of the first string with the second letter of the second string etc..
I started to do like this:
for(i=0, i<N, i++){
for(j=0, j<N, j++){
if(string1[i]==string1[j] etc.. etc..
}
}
I see clearly that it doesn't compare first letter with first letter, second with second etc..
So maybe anyone have an idea how can I do this? (Without using any functions of string.h, i want to do this ''on my own'').
Maybe its a stupid question but im still a novice in C so...
Ah and the last thing, I define the two strings with 5 characters in my example, but it could be more than 5 vs 5..
Thanks by advance for the ideas.
Edit 1 :
#include <stdio.h>
#define N 20
int main()
{
unsigned char string1[N], string2[N];
int Answer=0, i=0;
scanf("%s", string1);
scanf("%s", string2);
for(i=0; i<N; i++){
if(string1[i]==string2[i]){
Answer=1;
}
else{
Answer=0;
}
}
printf("Answer = %d", Answer);
return 0;
}
Why are you using a nested for loop for this? If both strings are of size n do this:
for(int i=0;i<n;i++){
if(string1[i]==string2[i]){
//do something
else if(// lesser than condition)
//do something else
else if(//greater than condition)
//do something else other than the previous something
}
Here you when i=0, you are comparing string1[0] with string2[0], when i=1, you compare string1[1] with string2[1] and so on.....
Your approach with nested loops isn't very well thought-out.
Clearly it will compare all letters of the second string against the first letter of the first string, then do the same for the second letter of the first string, and so on. Not at all the desired behavior.
Re-implementing strcmp() isn't very hard, here's a shot:
int my_strcmp(const char *a, const char *b)
{
for(; *a && *b && *a == *b; ++a, ++b)
;
if(*a < *b)
return -1;
return *a > *b;
}
Note that it returns zero when the strings are equal. A good way to write a test is:
if(my_strmcp(a, b) == 0)
{
printf("two equal strings: '%s' and '%s'\n", a, b);
}
Some people write it as if(!my_strcmp()) but I don't recommend that, since it's mashing up so many concepts.
You want to use the same index for both strings to compare:
unsigned len = strlen(s1);
assert(len == strlen(s2) && "Strings not the same length");
for (unsigned i = 0; i < len; i += 1)
{
if (s1[i] != s2[i])
return false; /* strings are not equal */
}
return true; /* strings are equal */
Make sure that the strings have the same encoding, either ASCII or UTF8 or whatever. Comparing strings of different encoding will cause trouble :)
This code compares character by character. Note that this is not suitable for crypto code as it is vulnerable to a timing attack
for(i=0; i<N; i++){
if(string1[i]==string2[i]){
equal = 1;
}else{
equal = 0;
break;
}
}
Notes:
I am assuming same length (as stated in question)
I am also assuming strings are non-zero length
Both of these assumptions may not be true in other code.
Simple compare each element until the end of string is found or a difference.
size_t i = 0;
while (string1[i] != '\0' && string1[i] == string2[j]) i++;
int StringTheSame = string1[i] == string2[j];
This ignores N, but stops when either end-of-string ('\0') is encountered.
[Edit] #Kartik_Koro suggested a concern about a timing attack. Following is a constant time solution
int diff_bits = 0;
for(size_t i=0; i<N; i++) {
diff_bits |= string1[i] ^ string2[i];
}
int equal = diff_bits == 0;
The above has a problem if either string's length is shorted than N-1, but per OP's requirements, that should not happen.