Checking for string null terminators in C - c

I know what the null-terminator in C is represented by \0 and has the numerical value of 0. However, when I execute the following code below, the program treats the null terminator as %. I searched this up online but I couldn't find anyone with this issue.
int main(){
char* forward = "hello";
int forward_length = 0;
while (*(forward++) != '\0') {
printf("%d\n", forward_length++);
}
if(*forward == '%'){
printf("Terminator Found");
}
}
The output is:
0
1
2
3
4
Terminator Found
Clearly, forward[5] does not equal the char %. Can someone please let me know what is wrong with the program?

The construction leaves forward advanced too far. This is because the post-increment will run even if the loop condition is false (as it is inside the loop condition). The obvious fixed loop is as follows:
for (;*forward != '\0'; ++forward)
printf("%d\n", forward_length++);
If you prefer to keep the while loop, --forward after the while loop will fix it.

Related

Iterate through an array of characters in C

Recently I saw this while loop condition in C in the example below but I have no idea what the while condition really means and how the compiler knows when it is done. Could someone explain it to me?
This is what I believe it means: while loop iterates through the char array until the ending of the array since there is nothing else then the while loop ends, or am I wrong? I tried to use the same while loop but in another language such as Go, however, the compiler threw an error saying that I cannot use a non-bool.
// C program to demonstrate
// example of tolower() function.
#include <ctype.h>
#include <stdio.h>
int main()
{
int j = 0;
char str[] = "GEEKSFORGEEKS\n";
// Character to be converted to lowercase
char ch = 'G';
// convert ch to lowercase using toLower()
char ch;
while (str[j]) { // <- this part, how is this a condition?
ch = str[j];
// convert ch to lowercase using toLower()
putchar(tolower(ch));
j++;
}
return 0;
}
the while loop can be understood as "while this string has characters" and as known in C strings or an array of chars contain a '\0' => Null character, in the end, once the while loop achieves it, it will stop the iteration.
So yeap! you are right.
You can think of an array of chars as following:
So as you see in the picture an array of chars is already a pointer, and each of the characters has an address, as well that the address of a pointer is the address of the first element, so when you declared
char str[] = "GEEKSFORGEEKS\n";
it was allocated in the memory like below:
[G][E][E][K][S][F][O][R][G][E][E][K][S][\n][\0]
The program will crash because you have a redeclaration of ch variable, as well there is no need to initialize the char ch = 'G'; since you're overriding it in the while loop and it will take str[j], and so you started iterating at j = 0 which the 1st index in the array [G], as you're incrementing the loop will go until the null character [\0] and stop because there's no iteration after the NULL, in other examples you might see the following condition in the loop: while(str[j] != '\0') which is similar to your condition but just more specific.
You can gain more performance by iterating through the pointer just like the following:
#include <ctype.h>
#include <stdio.h>
int main()
{
char *str = "GEEKSFORGEEKS\n";
while (*str)
putchar(tolower(*str++));
return 0;
}
Although, you got your answer. Still, I wanna add some more details or an explanatory answer here.
In C, a conditional statement will have either the value 1 or 0. In the end, they all are evaluated to Boolean values true or false or 1 or 0.
So first, try to understand or dry run that while(str[j]). Guess what will be the value of str[j] when j = 0. It'll be the first character "G". Similarly in the next iteration, you'll get the next character until NULL character or String Termination character. Now, anything in between those parentheses in while(str[j]) will be considered as a conditional statement and they all are evaluated to 1 or 0. Now here's the thing that anyhow if that conditional statement isn't being evaluated specifically to 0, then It'll be supposed to have the value of 1.
So, here str[j] when j = 0 will be evaluated as 1, then next character and so on. Now, when we find \0 which is an escape character equivalent to 0. So, at \0 while loop will terminate as the condition will be false.
Can, you tell me what will be the output of this program?
#include<stdio.h>
int main()
{
if(printf("Hello TraineeGuy\n"))
printf("TRUE");
else
printf("FALSE");
return 0;
}

Program keeps returning Segmentation Fault [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I'm a new person who loves to play around with coding. Recently I was going through a course on edx, and one of the exercises I need to complete has this small code snippet that keeps on giving Segmentation fault. I have taken out the faulty bit (everything else compiles nicely)
#include <stdio.h>
#include <string.h>
#include <cs50.h>
#include <ctype.h>
#include <stdlib.h>
int main (int argc, string argv[])
{
if (argc == 2 && isalpha(argv[1]))
{
int a = 0;
while (argv[1][a] == '\0')
{
a++;
printf("%c\n", argv[1][a]);
}
}
else
{
printf("Usage: ./programname 1-alphabetical word\n");
return 1;
}
}
The problem seems to be here: argv[1][a] but I can't for the life of me find out what, and how to fix it.
(1) isalpha(argv[1]) is wrong. This function expects a single character, but you are passing a pointer-to-string. That will certainly not give you any kind of expected result, and it's probably Undefined Behaviour into the bargain. You either need to loop and check each character, use a more high-level library function to check the entire string, or - as a quick and probably sense-changing fix - just check the 1st character as BLUEPIXY suggested: isalpha( argv[1][0] ) or isalpha( *argv[0] ).
(2) Your while condition is wrong. You are telling it to loop while the current character is NUL. This will do nothing for non-empty strings and hit the next problem #3 for an empty one. You presumably meant while (argv[1][a] != '\0'), i.e. to loop only until a NUL byte is reached.
(3) You increment index a before trying to printf() it. This will index out of range right now, if the input string is empty, as the body executes and then you immediately index beyond the terminating NUL. Even if the loop condition was fixed, you would miss the 1st character and then print the terminating NUL, neither of which make sense. You should only increment a once you have verified it is in-range and done what you need to do with it. So, printf() it, then increment it.
2 and 3 seem most easily soluble by using a for loop instead of manually splitting up the initialisation, testing, and incrementing of the loop variable. You should also use the correct type for indexing: in case you wanted to print a string with millions or billions of characters, an int is not wide enough, and it's just not good style. So:
#include <stddef.h> /* size_t */
for (size_t a = 0; argv[1][a] != '\0'; ++a) {
printf("%c\n", argv[1][a]);
}
isalpha(argv[1]) looks incorrect and should probably be isalpha(argv[1][0])
isalpha takes a character but you entered in a string to the function
another thing that sticks out as wrong is argv[1][a] == '\0' the ==
should be != this will mean that the while loop will stop once it hits the \0
perhaps
if (argc == 2)
{
int a = 0;
while (argv[1][a] != '\0')
{
if (isalpha(argv[1][a])
printf("%c\n", argv[1][a]);
a++;
}
}
may be what you are looking for?
The only reason for the segmentation fault I see is this subexpression of the if statement
if (argc == 2 && isalpha(argv[1]))
^^^^^^^^^^^^^^^^
There is specified an argument of an incorrect type. The expression argv[1] has the type char * while the function requires an object of character type that is interpreted as unsigned char and promoted to the type int.
So when the promoted argument has a negative value (except the EOF value) the function isalpha has undefined behavior.
From the C Standard (7.4 Character handling <ctype.h>)
1 The header <ctype.h> declares several functions useful for
classifying and mapping characters.198) In all cases the argument is
an int, the value of which shall be representable as an unsigned
char or shall equal the value of the macro EOF. If the argument has
any other value, the behavior is undefined.
You should write the if statement either like
if (argc == 2 && isalpha( ( unsigned char )argv[1][0] ) )
or like
if (argc == 2 && isalpha( ( unsigned char )*argv[1] ) )
Also there is a bug in the while statement that will execute never if the argument is not an empty string. I think you mean the following
int a = 0;
while ( argv[1][a] != '\0' )
{
printf("%c\n", argv[1][a]);
a++;
}
or for example like
int a = 0;
while ( argv[1][a] )
{
printf("%c\n", argv[1][a++]);
}

Compare character by character 2 strings

I am trying to code a program that tells me if 2 strings are identcal. If they have one different chracter they are not.
I have this code, but it does not work, why?
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main() {
char str1[30], str2[30];
int i;
printf("\nEnter two strings :");
gets(str1);
gets(str2);
for (i=0;str1[i]==str2[i];i++)
if (str1[i]!=str2[i]){
printf("They are not identical");
}
else continue;
return (0);
}
It compiles with 0 errors and 0 warnings, but when I introduce 2 not identical strings it returns nothing. (The same happens when I introduce 2 identical strings, but that is how is supposed to be)
What should I do to fix it?
There is one important thing wrong here. First of all: The classic "c style string" is null terminated. Allthough there are other alternatives (like storing the length outside of the string), the null terminated string is part of the language (as string literals in code are null terminated by the compiler), and the runtime library (most string functions handle the \0 at the end of the string).
gets also appends a \0 at the end of the entered string:
http://www.cplusplus.com/reference/cstdio/gets/
You are comparing not only the entered strings, but also anything (random) after that string in memory.
It should look like this:
for(int i=0;str1[i]==str2[i];i++){
if(str1[i]==0) {
printf("equal");
}
}
printf("not equal");
There are other alternative, like using pointer. But on modern compilers they should produce roughly the same machine code.
Please note that there are C runtime library functions to compare strings:
strcmp is the most basic one, just two char *:
strncmp allows to specify the maximium chars to compare, do compare a part of a string:
There are other, just check out the links.
Please note that it's better to use the library functions, because even if in such a "simple" function. There are optimized ways to compare string. Like comparing in native word sizes. On 32 bit platforms you spend four time more time in comparation, not including the masking needed to perform byte wise operations.
Your for loop is:
for (i=0;str1[i]==str2[i];i++)
if (str1[i]!=str2[i]){
printf("They are not identical");
}
else continue;
Let's say str1 is "abc" and str2 is "xyz".
The conditional in the for loop will evaluate to false for i = 0. Hence, you will never get to the statement:
if (str1[i]!=str2[i]){
Consequently, you will never execute:
printf("They are not identical");
You can fix the logic error by using:
for (i=0; str1[i] != '\0' && str2[i] != '\0'; i++)
{
if (str1[i]!=str2[i]) {
break;
}
}
// If at end of the loop, we have reached the ends
// of both strings, then they are identical. If we
// haven't reached the end of at least one string,
// then they are not identical.
if ( str1[i] != '\0' || str2[i] != '\0' )
{
printf("They are not identical");
}
I have this code, but it does not work, why?
Because your looping condition str1[i]==str2[i] will make the inner if condition be always false.
What should I do to fix it?
Simple code:
for ( i=0; str1[i]==str2[i] && str1[i]!='\0'; i++) {
}
if ( str1[i]!=str2[i] ) {
printf("They are not identical");
}
or
i=0;
while ( str1[i]==str2[i] && str1[i]!='\0' ) {
i++;
}
if ( str1[i]!=str2[i] ) {
printf("They are not identical");
}
Let's say you have two string in which the first character is different. then you will not enter the loop as the condition of the loop (str1[i]==str2[i]) fails, therefore the condition should be ( str1[i]!='\0' && str2[i]!='\0' ). The '\0' is the last character of the c-style string.
You can also use string built in functions like " strcmp(str1,str2) ".

what is wrong with my understanding of strings ie character arrays ending with '\0' element in C programming

I am a total beginner and recently started studying strings in C programming.
I understand that we need to supply the '\0' (null) character at the end of the string (to act as a end of string marker).
So if my character array is
char string[]={'H','E','L','L','O','\0'};
This makes it a 6 element array.
So I was going through this simple example of copying one string to another string. Here is the code.
#include<stdio.h>
int main()
{
char string1[80],string2[80];
int i;
printf("Enter a string \n");
gets(string2);
for(i=0; string2[i]!= '\0';i++)
{
string1[i]=string2[i];
}
string1[i]='\0'; /*here is my problem*/
printf("The copied string is \n");
printf("%s",string1);
printf("\n");
printf("The number of character are \t");
printf("%d \n",i);
}
why isn't it string1[i+1]='\0'??
I mean, isn't by putting string1[i]='\0' overwrite the last element that was just stored in the above for loop?
The code is correct, because of the way the for loop works:
for(A; B; C)
CODE;
Is equivalent to:
A;
while (B)
{
CODE;
C;
}
(Except for the use of continue, that will jump to the increment expression, not the condition, as it would happen with a while).
And since the loop ends when string2[i] != '\0', it is obvious that upon exiting, i is the index for the proper NUL byte. So after that:
string1[i] = '\0';
will write the \0 at the same place as it is in string2.
Usually for this kind of analysis it is helpful to think about preconditions and postconditions. That is, assuming there are no break and no goto, you are guaranteed that at the beginning of a for or while loop the condition is always true. And just after the end of a for or while loop the condition is always false.
Your particular code, illustrated with assert calls:
for(i=0; string2[i] != '\0'; i++)
{
asssert(string2[i] != '\0');
string1[i] = string2[i];
}
asssert(string2[i] == '\0');
string1[i] = '\0';
Looking at the code, it seems as if i is incremented as long as the character is not '\0'. So, the last time it's incremented, it increments to a new position that hasn't had a character written to it yet.
So, at the end of the loop, there's a space to write the null character to.

printf() isn't being executed

I wanted to write a program which counts the occurrences of each letter in a string, then prints one of each letter followed by the count for that letter.
For example:
aabbcccd -
Has 2 a, 2 b, 3 c, and 1 d
So I'd like to convert and print this as:
a2b2c3d1
I wrote code (see below) to perform this count/conversion but for some reason I'm not seeing any output.
#include<stdio.h>
main()
{
char array[]="aabbcccd";
char type,*count,*cp=array;
while(cp!='\0'){
type=*cp;
cp++;
count=cp;
int c;
for(c=1;*cp==type;c++,cp++);
*count='0'+c;
}
count++;
*count='\0';
printf("%s",array);
}
Can anyone help me understand why I'm not seeing any output from printf()?
char array[]="aabbcccd";
char type,*count,*cp=array;
while(cp!='\0'){
*cp is a pointer it's pointing to the address of the start of the array, it will never be == to a char '\0' so it can't leave the loop.
You need to deference the pointer to get what it's pointing at:
while(*cp != '\0') {
...
Also, you have a ; after your for loop, skipping the contents of it:
for(c=1;*cp==type;c++,cp++); <-- this ; makes it not execute the code beneath it
After fixing both of those problems the code produces an output:
mike#linux-4puc:~> ./a.out
a1b1c2cd
Not the one you wanted yet, but that fixes your problems with "printf not functional"
Incidentally, this code has a few other major problems:
You try to write past the end of the string if the last character appears once (you write a '1' where the trailing '\0' was, and a '\0' one character beyond that.
Your code doesn't work if a character appears more than 9 times ('0' + 10 is ':').
Your code doesn't work if a character appears more than 2 times ("dddd" doesn't become "d4"; it becomes "d4dd").
Probably line-buffering. Add a \n to your printf() formatting string. Also your code is very scary, what happens if there are more than 9 of the same character in a row?
1) error correction
while(*cp!='\0'){
and not
while(cp!='\0'){
2) advice
do not use array[] to put in your result user another array to put in your rusel it's more proper and eay
I tried to solve your question quickly and this is my code:
#include <stdio.h>
#define SIZE 255
int main()
{
char input[SIZE] = "aabbcccd";/*input string*/
char output[SIZE]={'\0'};/*where output string is stored*/
char seen[SIZE]={'\0'};/*store all chars already counted*/
char *ip = input;/*input pointer=ip*/
char *op = output;/*output pointer = op*/
char *sp = seen;/*seen pointer=sp*/
char c,count;
int i,j,done;
i=0;
while(i<SIZE && input[i]!='\0')
{
c=input[i];
//don't count if already searched:
done=0;
j=0;
while(j<SIZE)
{
if(c==seen[j])
{
done=1;
break;
}
j++;
}
if(done==0)
{//if i never searched char 'c':
*sp=c;
sp++;
*sp='\0';
//count how many "c" there are into input array:
count = '0';
j=0;
while(j<SIZE)
{
if(ip[j]==c)
{
count++;
}
j++;
}
*op=c;
op++;
*op=count;
op++;
}
i++;
}
*op='\0';
printf("input: %s\n",input);
printf("output: %s\n",output);
return 0;
}
It's not a good code for several reasons(I don't check arrays size writing new elements, I could stop searches at first empty item, and so on...) but you could think about it as a "start point" and improve it. You could take a look at standard library to copy substring elements and so on(i.e. strncpy).

Resources