Why does strlen() not represent the actual length of my string? - c

basically I have a string composed of multiple words like this: "Hello world test".
Either if I try to print it with a structure like this
printf("%s", string);
or like this
for (int i = 0; i < strlen(string); ++i) {
printf("%c", string[i];
}
I always get this as an output: Hello world and I get a strlen of 11 instead of 16 too.
If I try to print out the same exact string with an int counter that previously counts the single chars in the string
for (int i = 0; i < counter; ++i) {
printf("%c", string[i];
}
I actually get the correct output Hello world test, which leads be to believe that the elements are correctly assigned in the string but for some reason %s and strlen just ignores the ones after the last space.
Why would that happen? What is going on? How can I fix this?
EDIT:
Actual code as requested:
#include <stdio.h>
#include <string.h>
typedef int BOOL;
#define TRUE 1
#define FALSE 0
int main() {
char sentence[64] = " ", reversal[64] = " ", reversal_copy[64] = " ";
int index = 0, counter = 0;
BOOL reset = TRUE, last_cycle = FALSE;
printf("Enter a sentence: ");
for (int i = 0; sentence[strlen(sentence) - 1] != '\n'; i++) {
scanf("%c", &sentence[i]);
}
/* Copies the input in a string reversing it */
for (int h = strlen(sentence) - 2, k = 0; h >= 0; h--, k++) {
reversal[k] = sentence[h];
}
/* Detects the first character of a word and the last character of the same word before a space,
switching the first char with the last, the second with the pre-last and so on*/
for (int i = 0; i < strlen(reversal); i++) {
if (reset == TRUE) {
index = i;
reset = FALSE;
}
if (i == strlen(reversal) - 1) {
last_cycle = TRUE;
counter++;
}
if (reversal[i] != ' ') {
counter++;
if (last_cycle == TRUE) {
goto reversing;
}
}
else {
reversing:
for (int h = index, z = counter; h < counter; h++, z--) {
reversal_copy[h] = reversal[z - 1];
reversal_copy[z - 1] = reversal[h];
}
if (last_cycle == FALSE) {
reversal_copy[i] = ' ';
}
reset = TRUE;
counter++;
}
}
printf("%lu ", strlen(reversal_copy));
for (int i = 0; i < counter; i++) {
printf("%c", reversal_copy[i]);
}
printf("%s\n\n", reversal_copy);
return 0;
}

if strlen() returns 11 then you have a \0 char after the world "world".
strlen and printf both determine "what is a string" by using the 0 terminator, so no surprise that they behave the same.

While this is difficult to answer without a Minimal, Complete, and Verifiable example, I will explain the most likely reason for the behavior you're observing.
Both printf with the %s format specifier and strlen give you the length of the null-terminated string pointed to by the relevant argument. If they are printing/reporting a length of 11, but iterating through the entire char array with a hard-coded value of 16 gives you the output "hello world test", then the character after world is clearly the null character, '\0'.

Try running your program with the input "A" as an example - see that even a single word exhibits the problem.
Something is going wrong when you reverse the last word. You are putting the trailing '\0' in front of it. It probably has to do with the special casing and the goto around the last_cycle logic, which is very hard to follow.
I think it's probably related to the fact that you have two counter++s in that code path.
Consider using some functions to make the code cleaner:
len = strlen(reversal);
for (start=0; start<len; start++) {
end = find_space_or_null(reversal, start);
if (end > start) {
reverse_chars(reversal, start, end-1);
start = end;
}
}

the program takes a string inputted by the user like "the sky is blue" and prints out "blue is sky the"
That's a perfect job for strtok():
#include <stddef.h>
#include <stdio.h>
#include <string.h>
enum { MAX_LINE = 120 };
int main()
{
char buffer[MAX_LINE];
fgets(buffer, MAX_LINE, stdin);
size_t length = strlen(buffer);
if (length && buffer[length - 1] == '\n') // get rid of the newline
buffer[--length] = '\0';
char *tokens[MAX_LINE] = { 0 }; // there can't be more than 60 tokens, but hey
if ((tokens[0] = strtok(buffer, " ")) == NULL) // no tokens? nothing to do.
return 0;
size_t i = 1;
for (; tokens[i - 1] && i < sizeof(tokens); ++i)
tokens[i] = strtok(NULL, " "); // tokenize the buffer
--i; // the very last was NULL anyway.
while (--i) // print it reverse
printf("%s ", tokens[i]);
puts(buffer);
}
Sample Output:
The quick brown fox jumps over the lazy dog
dog lazy the over jumps fox brown quick The

Related

C - Reverse order of words in an array of Strings

I did this program to reverse the order of the words in the give string. (And it works)
i.e. Output: sentence first the is This
However I am stuck when it comes to adding another sentence to the array.
For example I need to have an array {"This is the first sentence", "And this is the second"} producing as output: sentence first the is This , second the is this And
int main() {
char str[] = {"This is the first sentence"};
int length = strlen(str);
// Traverse string from end
int i;
for (i = length - 1; i >= 0; i--) {
if (str[i] == ' ') {
// putting the NULL character at the position of space characters for
next iteration.
str[i] = '\0';
// Start from next character
printf("%s ", &(str[i]) + 1);
}
}
// printing the last word
printf("%s", str);
return 0;
}
I am new to C so its not surprising that I got stuck even if the solution is quite easy. Any help would be appreciated! Thanks!
Since you already have the code to print the words of one string in reverse order, I would suggest making that a function which takes a single string as an argument, i.e.:
void print_words_reverse(char * const str) {
// your current code here
}
Then you can call it separately for each string:
char strings[][30] = {
"This is the first sentence",
"And this is the second"
};
for (int i = 0; i < sizeof(strings) / sizeof(*strings); ++i) {
print_words_reverse(strings[i]);
}
Note that since you are modifying the string (by replacing spaces with NUL bytes), the argument needs to be modifiable, which means you are not allowed to call it (in standard C) with a pointer to a string literal, which means you can't simply use const char *strings[] = { "first", "second" }. You could get rid of the ugly constant length (here 30) reserved for every string by making your code not modify the argument string. Or you could have a separate char array for each sentence and then use pointers to those (modifiable) strings.
First, you can try with a two-dimensional array or use an array of pointers.
Secondly, in your approach, you lose the initial value of your string, I don't know how important it is.
This is my fast approach using arrray of pointers.
#include <stdio.h>
#include <string.h>
static void print_word(const char *str)
{
for (int i = 0; str[i] && str[i] != ' '; i++)
printf("%c", str[i]);
putchar(' ');
}
int main(void)
{
int len;
const char *str[] = {"This is the first sentence",
"And this is second", NULL};
for (int i = 0; str[i]; i++) {
for (len = strlen(str[i]); len >= 0; len--) {
if (len == 0)
print_word(&str[i][len]);
else if (str[i][len] == ' ')
print_word(&str[i][len + 1]);
}
putchar('\n');
}
printf("Initial value of array of strings [%s | %s] \n", str[0], str[1]);
return 0;
}
output is:
sentence first the is This
second is this And
Initial value of array of strings [This is the first sentence | And this is second]
I suggest you using memcpy but without altering too much your code this seems to work
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX_STRING_LENGTH 100
int main()
{
char *str[] = {"This is the first", "And this is the second sentence"};
const size_t NUM_STRING = sizeof(str)/sizeof(char*);
/*%z used to print size_t variables*/
printf("%zd strings found\n", NUM_STRING);
int length[2];
int i;
for (i=0; i<NUM_STRING; i++)
{
length[i] = strlen(str[i]);
}
printf("length initialized %d %d\n", length[0], length[1]);
// Traverse string from end
int j = 0;
char temp[MAX_STRING_LENGTH];
printf("\n\n");
for (j=0; j<NUM_STRING; j++)
{
/*Make sure the string respect the MAX_STRING_LENGTH limit*/
if (strlen(str[j])>MAX_STRING_LENGTH)
{
printf("ERROR: string %d exceding max string length %d defined in constant "
"MAX_STRING_LENGTH. Exiting from program.\n", j, MAX_STRING_LENGTH);
exit(1);
}
//reset temporary string
memset(temp, '\0', sizeof(temp));
//printf("temp variable reinitialized\n");
for (i = length[j] - 1; i >= 0; i--)
{
temp[i] = str[j][i];
if (str[j][i] == ' ')
{
// putting the NULL character at the position of space characters for next iteration.
temp[i] = '\0';
// Start from next character
printf("%s ", &(temp[i]) + 1);
}
}
// printing the last word
printf("%s ", temp);
}
printf("\n");
return 0;
}

Program to find the longest word in a string

I wrote a program to find the longest word in a string and print the number of letters in the longest word. But the code is not printing. I analyzed the program many times but I could not find the solution.
#include <stdio.h>
#include <string.h>
int main() {
char string[100] = "Hello Kurnool";
int i = 0, letters = 0, longest = 0;
start:
for (; string[i] !=' '; i++) {
letters++;
}
if (letters >= longest)
longest = letters;
if (string[i] == ' ') {
letters = 0;
i++;
goto start;
}
printf("%d", longest);
return 0;
}
Using goto is highly discouraged. You should convert your code to use a loop.
The main problem in your code is you do not stop the scan when you reach the end of the string.
Here is a modified version:
#include <stdio.h>
int main() {
char string[100] = "Hello Kurnool";
int i, letters, longest = 0, longest_pos = 0;
for (i = 0; string[i] != '\0'; i++) {
for (letters = 0; string[i] != '\0' && string[i] != ' '; i++) {
letters++;
}
if (letters > longest) {
longest = letters;
longest_pos = i - longest;
}
}
printf("longest word: %d letters, '%.*s'\n",
longest, longest, string + longest_pos);
return 0;
}
Note that the implementation can be simplified into a single loop:
#include <stdio.h>
int main() {
char string[100] = "Hello Kurnool";
int i, start = 0, longest = 0, longest_pos = 0;
for (i = 0; string[i] != '\0'; i++) {
if (string[i] == ' ') {
start = i + 1;
} else {
if (i - start > longest) {
longest = i - start;
longest_pos = start;
}
}
}
printf("longest word: %d letters, '%.*s'\n",
longest, longest, string + longest_pos);
return 0;
}
Below is my approach. You should use C's string manipulation functions. This is the correct way to deal with strings in C.
In the code below, first I acquire the required bytes to store the input string in heap. Then I use strtok to split the string into tokens based on a delemeter and get the length of each sub string. Finally I free the space that I have allocated with malloc.
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define phrase "Hello Kurnool"
int main()
{
char* string = malloc(strlen(phrase)+1);
strcpy(string,phrase);
int longest=0;
char *token;
char delimeter[2] = " ";
/* get the first token */
token = strtok(string, delimeter);
/* walk through other tokens */
while( token != NULL ) {
printf( " %s\n", token );
if(longest < strlen(token)){
longest = strlen(token);
}
token = strtok(NULL, delimeter);
}
printf("%d",longest);
free(string);
return 0;
}
People say - dont use goto but there is nothing inherently wrong with goto. Only thing is if goto is not used judiciously, it makes code more difficult to understand and maintain. For example, the way you have used it in your program ( instead of goto, a loop is perfect fit in such cases). Check this:
To use goto or not?
What is wrong with using goto?
Coming to your code, the for loop condition does not have check for terminating null character
for (; string[i] !=' '; i++) {
Hence it will not stop at the end of string.
To find the number of letters in longest word of string, you can do:
#include <stdio.h>
#include <string.h>
int main() {
char string[100] = "Hello Kurnool";
int i, letters = 0, longest = 0;
for (i = 0; string[i] != '\0'; i++) {
if (string[i] != ' ') {
letters++;
if (letters > longest) {
longest = letters;
}
} else {
letters = 0;
}
}
printf("longest : %d\n", longest);
return 0;
}
First of all,Please avoid using Goto, it is not a good practice.
Secondly, your loop will run infinite times when it iterates the second time because:
for(;string[i]!=' ';i++) // Here String[i] will never be equal to ' ' As there is no white space after your last word.
You can never expect what might be going wrong with your program if you are using
goto statement
which is never advisable to use rather it's bad programming if you use it. Secondly it looks like you are stuck in an infinite loop so her is a solution to your problem:
#include<stdio.h>
#include<string.h>
void main()
{
char s[1000];
scanf("%s",s);
int i=0;
int letters;
int longest=0;
while(s[i]!=NULL)
{
if(s[i]==' ')
{
if(longest>=letters)
{longest=letters;}
letters=0;
}
else
{letters++;}
}
printf("%d\n",longest);
}
So, what I have done is assuming a string s which is the input given by the user. You itterate through s till the last input given by the user after which it encounters a NULL character. Now you are searching for the length of the longest word, so you create a variable letters for counting the no. of letters in each word of the string. And if the string s encounters a space indicating the end of a word, then you check if the variable longest is greater than or less than the word count. And again you initialize letters to 0, so that it can start counting the next word from 0 again.So, by this method at the end i.e. after the while loop terminates we get our required output which is stored in the variable longest.
So, I guess this will print the no. of letters in the longest word.

Memory limit exceeded in C

I'm currently being a tutor for a student in C. For his classes, the university has installed a server running Mooshak (software capable of receiving code and test it).
We have developed code, compiled it and tested it locally before sending to the server and everything went fine. However, when we tried to send it to the server, the server stated "Memory Limit Exceeded".
The code looked as follows:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <limits.h>
#include <string.h>
#define LIMITE_CARACTERES 1000
#define LIMITE_GENES 100000
char genes[LIMITE_GENES][LIMITE_CARACTERES];
char* copiar_por_espaco(char* string, char* dest)
{
for(int i = 0; i < strlen(string); i++)
{
if(' ' == string[i])
{
strncpy(dest, string, i);
dest[i] ='\0';
if( i + 1 >= strlen(string))
return NULL;
else
return &string[i+1];
}
}
if(strlen(string) == 0)
{
return NULL;
}
else
{
strcpy(dest, string);
return NULL;
}
}
void genes_f()
{
char s[LIMITE_CARACTERES];
int numero_genes = 0;
while(scanf("%s", s) != EOF)
{
char *auxiliar = s;
while(auxiliar != NULL && strlen(auxiliar) != 0)
{
auxiliar = copiar_por_espaco(auxiliar, genes[numero_genes]);
numero_genes++;
}
}
if(numero_genes <= 20)
{
for(int i = 0; i < numero_genes; i++)
{
printf("%s\n", genes[i]);
}
}
else
{
for(int i = 0; i < 10; i++)
{
printf("%s\n", genes[i]);
}
for(int i = numero_genes - 10; i < numero_genes;i++)
{
printf("%s\n", genes[i]);
}
}
}
int main()
{
genes_f();
return 0;
}
Please note that the values LIMITE_CARACTERES and LIMITE_GENES are an assignment requirement (they haven't been told about memory allocation yet). The above code gives the "Memory Limit Exceeded", but if I split the first four into two lines, the server does not throw that error and accepts our solution:
char* copiar_por_espaco(char* string, char* dest)
{
int len = strlen(string); // This line was taken out from the for
for(int i = 0; i < len; i++) // Now we used the variable instead
{
if(' ' == string[i])
{
strncpy(dest, string, i);
dest[i] ='\0';
if( i + 1 >= strlen(string))
return NULL;
else
return &string[i+1];
}
}
if(strlen(string) == 0)
{
return NULL;
}
else
{
strcpy(dest, string);
return NULL;
}
}
I have no idea why. Is there an explanation for this?
The input will several lines with words (blank lines should be skipped), separated by a space. The program should separate and take each word:
Input
A BDD TES QURJ
test dog cat heart
cow
bird tree
Output
A
BDD
TES
QURJ
test
dog
cat
heart
cow
bird
tree
You forgot to include an extra byte for null terminators in your array. If LIMITE_CARACTERES is the maximum length of a string provided as input, then you need an array of size LIMITE_CARACTERES + 1 in which to store it. So you need to change this line
char genes[LIMITE_GENES][LIMITE_CARACTERES];
to
char genes[LIMITE_GENES][LIMITE_CARACTERES + 1];
Since you are a tutor, I give feedback so you can properly teach your student (so this is not an answer to your problem).
copiar_por_espaco
for(int i = 0; i < strlen(string); i++)
Repeatedly calling strlen on a variable that does not change in the loop is a waste of CPU cycles. Indeed, you should calculate the length before the loop and use it in the loop. That also holds for if( i + 1 >= strlen(string))
if(' ' == string[i])...
Note that it is guaranteed the string does not hold spaces because it was read with scanf. As a consequence, the function will always return NULL.
if(strlen(string) == 0) return NULL;
You test this after the loop but logic dictates you do this before any processing and it could be shortened to if (!*string) return NULL; This would also make the code more beautiful as the else part is not needed (it is not needed anyway).
genes_f
while(scanf("%s", s) != EOF)
A scanf-guru might help here but I believe there must be a space in the format specifier so it will skip leading spaces, " %s". I believe your way will read only one string and then will loop indefinitely returning zero on each scanf call. You should test the result of scanf for the number of format specifiers successfully converted and not for EOF. So check for 1.
if(numero_genes <= 20)
Your printing is funny. It all can be as one loop:
for(int i = numero_genes; i < numero_genes; i++)
printf("%s\n", genes[i]);
You have to do bounds checks on your number of genes:
numero_genes<LIMITE_GENES

C Programming: Counting word length occurences in a string

How would you be able to count word lengths and output their occurrences from a string using gets() or fgets()? For example, here is code doing so but using getchar()below. I think writing it in gets() would make it easier to incorporate all of the delimiters in the program rather than having to manually set if statements for each one of those would it not?
#include <string.h>
#include <ctype.h>
const char delim[] = ", . - !*()&^%$##<> ? []{}\\ / \"";
#define SIZE 100
int main(void){
int length[SIZE] = { 0 };
int name[SIZE];
int i = 0, ch, word_len = 0;
int count = 0;
printf("enter sentence: ");
while (1){
ch = getchar();
if (isalpha(ch)){
++word_len;
}
else if (ch == ' ' || ch == '.'){
if (word_len)
length[word_len - 1]++;//-1: to 0 origin
if (ch == '.')
break;
word_len = 0;
}
}
printf("Word Length \tCount \n");
for (i = 0; i<sizeof(length) / sizeof(*length); ++i){
if (length[i])
printf(" %d \t\t%d\n", i + 1, length[i]);
}
return 0;
}
You can build your custom delimiter detection function.
// globals
const char *delim = " .,;:!?\n\0";
const int n_delim = 9;
int is_delim(int c)
{
register int i;
for (i = 0; i < n_delim; i++)
if (c == delim[i]) return 1;
return 0;
}
This function will return 1 every time it can match c with delim. So you can use it like this:
fgets(buffer, 200, stdin);
for (i = 0; i < strlen(buffer); i++) {
if (is_delim(buffer[i])) {
wl[words++] = length;
length = 0;
continue;
}
length++;
}
I'm assuming you're familiar with the fgets function.
You basically will loop through your buffer, making comparisons with each character. Every loop iteration you check if the current character is a word delimiter, if it is, you save the current length and set length=0 for a new word, and at every iteration you increment the length.
You'll need to come up with a way of either not inserting the zero length values due to double delimiters or just ignore them when you're printing the results.
Basically you want to split a string into words, based on some delimiters, and compute their length. The C standard library provides the strtok function, which does exactly what you need: it splits the given string into multiple tokens.

Word length frequency in C Program

I am trying to write a simple C program to output the length of words and output their frequencies. For example, if the user inputs "hey" my program would output Length of word: 3 Occurrences 1, and so on with a larger string inputted. I just cannot seem to loop it properly. I thought of setting both counters when a delimiter is seen to count both the length of the word at the time and its occurrence but I have not found a way for it to work. How can I fix my loop? My code is below. I'd appreciate any help. I should include my program only runs correctly for one word inputted but not a whole sentence or multiple sentences.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
const char delim[] = ", . - !*()&^%$##<> ? []{}\\ / \"";
const int n_delim = 31;
#define SIZE 1000
int is_delim(int c);
int main(){
char string[SIZE];
int wordlength = 0, wl[SIZE];
int word = 0, i;
printf("Enter your input string:");
fgets(string, SIZE, stdin);
string[strlen(string) - 1] = '\0';
printf("Word Length\tCount\n");
int seen = 0;
int l;
for (i = 0; i < strlen(string); i++){
if (is_delim(string[i])){
wl[word++] = wordlength;
l = wordlength;
seen++;
printf("%d\t\t%d\n", l, seen);
wordlength = 0;
}
wordlength++;
}
return 0;
}
int is_delim(int c){
register int i;
for (i = 0; i < n_delim; i++)
if (c == delim[i]) return 1;
return 0;
}
The trick is that wl[n] holds the count of words
of length n. Also, you don't need to keep calling strlen()
on every iteration, just check for the zero byte at the end.
The optimizer will do this for you, if you enable it.
The odd-looking for(;1;) is so that the loop counts
the final word, which is terminated by the zero byte.
memset(wl,0,sizeof(wl));
for(wordStart=maxLength=i=0;1;i++) {
if(is_delim(string[i]) || string[i]==0) {
int wordLength= i-wordStart;
if(wordLength>0)
wl[wordLength]++;
if(wordLength>maxLength)
maxLength= wordLength;
wordStart= i+1;
}
if(string[i]==0)
break;
}
for(i=1;i<=maxLength;i++) {
if(wl[i]>0) {
printf("%d words of length %d.\n",wl[i],i);
}
}
You really should use strtok for this. Right now, you never compare the last string with the current one so you can't tell them apart. You can use strcmp for this. Finally instead of manually testing the length of the string you should use strlen. Here is how your loop could look like
int seen = 0;
pch = strtok(string, delim);
last = pch;
while(pch != NULL) {
if(strcmp(last, pch) != 0) {
printf("%s:\t%d\t\t%d\n", last, (int)strlen(last), seen);
seen = 1;
}else {
seen++;
}
last = pch;
pch = strtok(NULL, delim);
}
printf("%s:\t%d\t\t%d\n", last, (int)strlen(last), seen);
Note, you should set the variable seen to 0 before the loop.

Resources