Respected Experts ,
I am a newbie to C programming Language .
I am trying to print a string in C Language . The code runs successfully but when i
enter the string , it does not displays the string entered by the user in return
I have attached the screenshot of the code which I am trying to execute .
Please help me out .
#include<stdio.h>
int main()
{
char str[20];
char *pt;
printf("Enter any string :\n");
gets(str);
pt=&str[0];
for(*pt=0; *pt != '\0'; *pt++)
{
printf("%c", *pt);
}
}
The initialization *pt = 0; is causing the continuation test *pt != 0 to fail immediately, so your loop stops before printing anything.
You already initialized pt before the loop, so you don't need that step in the for() header. And you should be incrementing the pointer, not the character that it points so, so the update should be pt++.
for (; *pt != '\0'; pt++) {
printf("%c", *pt);
}
BTW, ptr = &str[0]; can be simplified to just ptr = str;. It's also more idiomatic to put this in the for header, so it would be:
for (pt = str; *pt != '\0'; pt++)
First - NEVER NEVER NEVER use gets, not even in toy code. It was deprecated in the 1999 standard and has been removed from the standard library as of the 2011 standard. It will introduce a point of failure / major security hole in your code. Use fgets instead, just be aware it will store the newline to your buffer if there's room.
Restructure your for statement as follows:
for ( pt = str; *pt != '\0'; pt++ )
The first expression sets pt to point to the first character in str (in this context, str is equivalent to &str[0]). The second compares the value of the element that pt points to against the string terminator. Since you are trying to check the value of the pointed-to object, you must use the * operator to deference pt. The final expression advances pt to point to the next character in the string.
Finally, is there a reason you're printing the string out character by character instead of just writing printf( "%s\n", str ); ?
Related
i just saw this "while(something);" syntax. i googled this but did not found anything. how does this work? especially second while in the example code confuses me.
this code is a program to concatenate two strings using pointer.
#include <stdio.h>
#define MAX_SIZE 100 // Maximum string size
int main()
{
char str1[MAX_SIZE], str2[MAX_SIZE];
char * s1 = str1;
char * s2 = str2;
/* Input two strings from user */
printf("Enter first string: ");
gets(str1);
printf("Enter second string: ");
gets(str2);
/* !!!!!!!!!!!!!!!!! this is it!!!!!!!!!!!!!!!!!!!! Move till the end of str1 */
while(*(++s1));
/* !!!!!!!!!!!!!!!!! this is it!!!!!!!!!!!!!!!!!!!! Copy str2 to str1 */
while(*(s1++) = *(s2++));
printf("Concatenated string = %s", str1);
return 0;
}
The while loop is defined in C the following way
while ( expression ) statement
In this while loop
while(*(++s1));
the statement is a null statement. (The C Standard, 6.8.3 Expression and null statements)
3 A null statement (consisting of just a semicolon) performs no
operations.
So in the above while loop the expression is evaluated cyclically until it logically becomes false.
Pay attention to that this while loop has a bug.;)
Let's assume that the pointed string is empty "". In memory it is represented the following way
{ '\0' }
So initially s1 points to the terminating zero.
But before dereferencing it is incremented in the expression of the while loop
while(*(++s1));
^^^^
and after that points in the uninitialized part of the character array after the terminating zero '\0'. So the loop can invoke undefined behavior.
It would be more correctly to rewrite it like
while( *s1 != '\0' ) ++s1;
In this case after the loop the pointer s1 will point to the terminating zero '\0' of the source string.
This while loop where the statement is again a null statement
while(*(s1++) = *(s2++));
can be rewritten the following way
while( ( *s1++ = *s2++ ) != '\0' );
that is in essence the same as
while( ( *s1 = *s2 ) != '\0' )
{
++s1;
++s2;
}
(except that if the terminating zero was encountered and copied the pointers are not incremented)
That is the result of the assignment ( *s1 = *s2 ) is the assigned character that is checked whether it is equal already to the terminating zero character '\0'. And if so the loop stops and it means that the string pointed to by the pointer s2 is appended to the string pointed to by the pointer s1.
Pay attention to that the function gets is unsafe and is not supported by the C Standard. Instead you should use the function fgets as for example
#include <string.h>
#include <stdio.h>
//...
printf("Enter first string: ");
fgets(str1, sizeof( str1 ), stdin );
str1[ strcspn( str1, "\n" ) ] = '\0';
The last statement is used to remove the new line character '\n' that can be appended to the entered string by the function call.
Also you need to check in the program whether there is enough space in the array str1 and the string stored in the array str2 can be indeed appended to the string stored in the array str1.
while(*(++s1)); is an obfuscated and bugged way of writing while(*s1 != '\0') { s1++; }.
(It should have been while(*(s1++)); to behave as expected, but that too is wrong since it increments the pointer upon failure and won't work with an empty string.)
while(*(s1++) = *(s2++)); is an obfuscated (and likely inefficient) way of writing strcpy(s1,s2);.
The whole program is an obfuscated way of writing strcat(s1, s2);. You can replace both of these buggy while loops with that single function call.
Generally while(something); is bad practice, to the point where compilers might even warn for it, since it isn't clear if the semicolon ended up there on purpose or by a slip of the finger. Preferred style is either:
while(something)
; // aha this was surely not placed there by accident
or
while(something){}
or
while(something)
{}
++s1 advances (or increments) the pointer, before the while checks it value
The while loop will iterate through the string until it will reach the null terminator, since while(NULL) is equal to while(false) or while(0)
The loop
while(*(++s1));
doesn't need a body because everything is done inside the loop condition.
Therefore the loop body is an empty statement ;.
The loop consists the following steps:
++s1 increment pointer
*(...) dereference pointer, i.e. get the data where the pointer points to.
use the value as the condition (0 is false, everything else is true)
The loop can be rewritten as
do
{
++s1;
}
while(*s1); // or while(*s1 != '\0');
Similarly, the other loop
while(*(s1++) = *(s2++));
can be written as
do
{
char c;
*s1 = *s2;
c = *s1;
s1++;
s2++;
}
while(c != '\0')
Note that the original loop condition contains an assignment (=), not a comparison (==). The assigned value is used as the loop condition.
I started learning C and I had this exercise from the book "Prentice Hall - The C Programming Language".
Chapter 5 Exercise 3:
Write a pointer version of the fuction strcat that we showed in Chapter 2. strcat(s, t) copies the string t to the end of s.
I did the exercise but the first method that came up to my mind was:
void stringcat(char *s, char *t){
int i,j;
i = j = 0;
while(*(s+i) != '\0'){
printf("%d", i);
i++;
}
while ( (*(t+j)) != '\0'){
*(s+i) = *(t+j);
i++;
j++;
}
}
In main I had:
int main(){
char s[] = "Hola";
char t[] = "lala";
stringcat(s,t);
printf("%s\n", s);
}
At first sight I thought it was right but the actual output was Holalalaa.
Of course it was not the output that I expected, but then I coded this:
void stringcat(char *s, char *t){
int i,j;
i = j = 0;
while(*(s+i) != '\0'){
printf("%d", i);
i++;
}
while((*(s+i) = *(t+j)) != '\0'){
i++;
j++;
}
}
And the output was right.
But then I was thinking a lot about the first code because it's very similar to the second one but why the first output was wrong?. Is it something related with the while statement? or something with pointers?. I found it really hard to understand because you can't see what's happening in the array.
Thanks a lot.
Your code has more than the one problem that you found, but let's start with it.
Actually you are asking why
/* ... */
while ((*(t+j)) != '\0') {
*(s+i) = *(t+j);
/* ... */
works differently than
/* ... */
while ((*(s+i) = *(t+j)) != '\0') {
/* ... */
I hope you see it already, now that both cases stand side by side, actually vertically ;-). In the first case the value of t[j] is compared before it is copied to s[i]. In the second case the comparison is done after the copy. That's why the second case copies the terminating '\0' to the target string, and the first case does not.
The output you get works accidentally, it is Undefined Behavior, since you are writing beyond the border of the target array. Fortunately for you, both strings are laying in sequence in the memory, and you are overwriting the source string with its own characters.
Because your first case does not copy the '\0', the final printf() outputs more characters until a '\0' is encountered. By chance this is the last 'a'.
As others commented, the target string has not enough space for the concatenated string. Provide some more space like this:
char s[10] = "Hola"; /* 10 is enough for both strings and the terminating '\0'. */
However, if you had done this already, the error would have not been revealed, because the last 6 characters of s are initialized with '\0'. Not copying the terminating '\0' makes no difference. You can see this if you use
char s[10] = "Hola\0xxxx";
I don't think that your solution is the expected one. Instead of s[i] you are using *(s + i), which is essentially the same, accessing an array. Consider changing s (and in the course, t) in the function and use just *s.
Side note: The printf() in the function is most probably a leftover from debugging. But I'm sure you know.
I seem to have some trouble getting my string to terminate with a \0. I'm not sure if this the problem, so I decided to make a post.
First of all, I declared my strings as:
char *input2[5];
Later in the program, I added this line of code to convert all remaining unused slots to become \0, changing them all to become null terminators. Could've done with a for loop, but yea.
while (c != 4) {
input2[c] = '\0';
c++;
}
In Eclipse when in debug mode, I see that the empty slots now contain 0x0, not \0. Are these the same things? The other string where I declared it as
char input[15] = "";
shows \000 when in debug mode though.
My problem is that I am getting segmentation faults (on Debian VM. Works on my Linux 12.04 though). My GUESS is that because the string hasn't really been terminated, the compiler doesn't know when it stops and thus continues to try to access memory in the array when it is clearly already out of bound.
Edit: I will try to answer all other questions soon, but when I change my string declaration to the other suggested one, my program crashes. There is a strtok() function, used to chop my fgets input into strings and then putting them into my input2 array.
So,
input1[0] = 'l'
input1[1] = 's'
input1[2] = '\n'
input2[0] = "ls".
This is a shell simulating program with fork and execvp. I will post more code soon.
Regarding the suggestion:
char *input2[5]; This is a perfectly legal declaration, but it
defined input2 as an array of pointers. To contain a string, it needs
to be an array of char.
I will try that change again. I did try that earlier, but I remember it giving me another run-time error (seg fault?). I think it is because of the way I implemented my strtok() function though. I will check it out again. Thanks!
EDIT 2: I added a response below to update my progress so far. Thanks for all the help!
It is here.
.
You code should rather look like this:
char input2[5];
for (int c=0; c < 4; c++) {
input2[c] = '\0';
}
0x0 and \0 are different representation of the same value 0;
Response 1:
Thanks for all the answers!
I made some changes from the responses, but I reverted the char suggestion (or correct string declaration) because like someone pointed out, I have a strtok function. Strtok requires me to send in a char *, so I reverted back to what I originally had (char * input[5]). I posted my code up to strtok below. My problem is that the program works fine in my Ubuntu 12.04, but gives me a segfault error when I try to run it on the Debian VM.
I am pretty confused as I originally thought the error was because the compiler was trying to access an array index that is already out of bound. That doesn't seem like the problem because a lot of people mentioned that 0x0 is just another way of writing \000. I have posted my debug window's variable section below. Everything seems right though as far as I can see.. hmm..
Input2[0] and input[0], input[1 ] are the focus points.
Here is my code up to the strtok function. The rest is just fork and then execvp call:
int flag = 0;
int i = 0;
int status;
char *s; //for strchr, strtok
char input[15] = "";
char *input2[5];
//char input2[5];
//Prompt
printf("Please enter prompt:\n");
//Reads in input
fgets(input, 100, stdin);
//Remove \n
int len = strlen(input);
if (len > 0 && input[len-1] == '\n')
input[len-1] = ' ';
//At end of string (numb of args), add \0
//Check for & via strchr
s = strchr (input, '&');
if (s != NULL) { //If there is a &
printf("'&' detected. Program not waiting.\n");
//printf ("'&' Found at %s\n", s);
flag = 1;
}
//Now for strtok
input2[i] = strtok(input, " "); //strtok: returns a pointer to the last token found in string, so must declare
//input2 as char * I believe
while(input2[i] != NULL)
{
input2[++i] = strtok( NULL, " ");
}
if (flag == 1) {
i = i - 1; //Removes & from total number of arguments
}
//Sets null terminator for unused slots. (Is this step necessary? Does the C compiler know when to stop?)
int c = i;
while (c < 5) {
input2[c] = '\0';
c++;
}
Q: Why didn't you declare your string char input[5];? Do you really need the extra level of indirection?
Q: while (c < 4) is safer. And be sure to initialize "c"!
And yes, "0x0" in the debugger and '\0' in your source code are "the same thing".
SUGGESTED CHANGE:
char input2[5];
...
c = 0;
while (c < 4) {
input2[c] = '\0';
c++;
}
This will almost certainly fix your segmentation violation.
char *input2[5];
This is a perfectly legal declaration, but it defined input2 as an array of pointers. To contain a string, it needs to be an array of char.
while (c != 4) {
input2[c] = '\0';
c++;
}
Again, this is legal, but since input2 is an array of pointers, input2[c] is a pointer (of type char*). The rules for null pointer constants are such that '\0' is a valid null pointer constant. The assignment is equivalent to:
input2[c] = NULL;
I don't know what you're trying to do with input2. If you pass it to a function expecting a char* that points to a string, your code won't compile -- or at least you'll get a warning.
But if you want input2 to hold a string, it needs to be defined as:
char input2[5];
It's just unfortunate that the error you made happens to be one that a C compiler doesn't necessarily diagnose. (There are too many different flavors of "zero" in C, and they're often quietly interchangeable.)
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
Can someone explain this reverse sentence code for me? How does the first and the second looping works? What's the point of each of them?
main(){
char arr[255], *p;
printf("Enter string: ");
gets(arr);
for(p=arr; *p!='\0'; p++);
for(p--; p>=arr; p--){
printf("%c",*p);
}
}
Input:
I love you
Output:
uoy evol I
The code is basically printing in reverse the input array.
for(p=arr; *p!='\0'; p++);
Sets p as the last (relevant) element of the array (the null character)
for(p--; p>=arr; p--){
printf("%c",*p);
}
starts from the last (none null) character and prints each one from last to first.
Question for you:
What happens if the input array is longet than 255 chars? (answer below)
buffer overflow
Suppose the input is Hello World. This gets stored in your buffer arr as
[H][e][l][l][o][ ][W][o][r][l][d][\0]...
Your pointer is set to arr, hence the pointer points to H
[H][e][l][l][o][ ][W][o][r][l][d][\0]...
^
|
p
The first loop advances (p++) until it meets the first null character (\0). It now looks like
[H][e][l][l][o][ ][W][o][r][l][d][\0]...
^
|
p
Now the second loop goes back (p--) until it reaches the first character again (actually, until the pointer equals the pointer to the beginning of the array), printing each character as it meets it. The first character \0 however is ignored with the little p-- here:
for(p--; p>=arr; p--)
^^^
The code looks clever, but it actually exhibits undefined behavior, which means the code may do anything.
The problem is the second loop:
for(p--; p>=arr; p--){
printf("%c",*p);
}
What it's intended to do is to start p at the last character of the string (excluding the terminating \0, then keep decrementing it until all the characters of the string have been output in reverse order.
The problem is the termination condition: after the intended end of the loop, p is arr, and then p-- subtracts one, and then p >= arr is false.
Unfortunately, an arithmetic operation on pointers may not result in a pointer that no longer points to the object (or one after the final object of an array), or it's undefined behavior.
That's what's happening here: p-- causes p to be off the array, and all bets are off as to what happens next.
Here's a correct way to write the second loop:
for (int i = (p-arr)-1; i >= 0; i--) {
printf("%c", p[i]);
}
I'd probably write the entire code using indexes to completely avoid pointer arithmetic. Maybe something like this:
int i = 0;
// Find the terminating \0 byte
while(p[i])i++;
// Iterate backwards through the string, outputting characters along the way.
while(--i >= 0)putc(p[i]);
Before explaining the code, I must say two things - first, the signature of the main function should be one of the following -
int main(void);
int main(int argc, char *argv[]);
and second, do not use gets. It's not safe to use. Use fgets instead. Now, coming to the code.
for(p = arr; *p != '\0'; p++) ;
In the above loop, p is assigned the base address of the array arr, i.e., the address of the first element of the array arr. The array arr contains a terminating null byte which means it is a string. The loop body is the null statement ; which means p is incremented till the null byte is encountered, i.e., when the test *p != '\0' fails. In the for loop
for(p--; p >= arr; p--) {
printf("%c",*p);
}
p is first decremented to point to the last character just before the null byte and then it is printed in each iteration till the condition p >= arr is true, i.e., till the first element of the array is reached. You should change your code to -
#include <stdio.h>
int main(void) {
char arr[255], *p;
printf("Enter string:\n");
fgets(arr, sizeof arr, stdin);
for(p = arr; *p! = '\0'; p++)
; // the null statement
for(p--; p >= arr; p--)
printf("%c", *p);
return 0;
}
I'm dusting off of my C skills for an upcoming class and I came across this weird output with printf after building a string using getchar. Specifically, any string I try to output gets the same sequence of characters appended to each letter. foo becomes "f?8#{?o?8#{?o?8#{?" compiling with cc, and f¿:¿o¿:¿0¿:¿ with Apple LLVM 5.0 (Xcode). Here is the sample code that illustrates the issue:
char * input_buffer = malloc( sizeof( char ) );
char c;
while ( ( c = getchar() ) != '\n' ) {
strcat(input_buffer, &c);
}
// problem output
printf( "\n%s\n", input_buffer );
// foo -> f¿:¿o¿:¿0¿:¿
// weird side effect is the 4 is required to get a proper len
printf("\ncharacters: %lu\n", strlen( input_buffer ) / 4 );
I've searched everywhere but I'm not seeing this anywhere else, but then this seems like a bit of an edge case. Is this is some kind of an encoding issue that I am not taking into account?
You cannot call strcat(input_buffer, &c);.
Each of the arguments passed to strcat must be a valid null-terminated string of characters.
The chances of the next byte after &c being 0 are pretty slim.
The chances of the first byte pointed by input_buffer being 0 aren't very high either.
In other words, strcat reads "junk" until it encounters a 0 character, in both arguments.
Change:
while ( ( c = getchar() ) != '\n' ) {
strcat(input_buffer, &c);
}
To:
for (int i=0; 1; i++)
{
c = getchar();
if (c == '\r' || c == '\n')
{
input_buffer[i] = 0;
break;
}
input_buffer[i] = c;
}
You are allocating space to input_buffer for only one char.
strcat(input_buffer, &c); is wrong. You are concatenating character (it is not null terminated) with a string.
getchar returns int type but you declared c is of type char.
char * input_buffer = malloc( sizeof( char ) );
sizeof (char) is 1 by definition. This allocates space for a single character, and makes input_buffer point to it.
You're also not checking whether the allocation succeeded. malloc returns a null pointer on failure; you should always check for that.
And the allocated char object that input_buffer points to contains garbage.
char c;
while ( ( c = getchar() ) != '\n' ) {
strcat(input_buffer, &c);
}
getchar() returns an int, not a char. You can assign the result to a char object, but by doing so you lose the ability to detect and end-of-file or error condition. getchar() returns EOF when there are no more characters to be read; you should always check for that, and doing so requires storing the result in an int. (EOF is an integer value that's unequal to any valid character.)
strcat(input_buffer, &c);
input_buffer points to a single uninitialized char. You can treat it as an array consisting of a single char element. The first argument to strcat must already contain a valid null-terminated string, and it must have enough space to hold that string plus whatever you're appending to it.
c is a single char object, containing whatever character you just read with getchar(). The second argument tostrcatis achar*, so you've got the right type -- but thatchar*` must point to a valid null-terminated string.
strcat will first scan the array pointed to by input_buffer to find the terminating '\0' character so it knows where to start appending -- and it will probably scan into memory that's not part of any object you've declared or allocated, possibly crashing your program. If that doesn't blow up, it will then copy characters starting at c, and going past it into memory that you don't own. You have multiple forms of undefined behavior.
You don't need to use strcat to append a single character to a string; you can just assign it.
Here's a simple example:
char input_buffer[100];
int i = 0; /* index into input_buffer */
int c;
while ((c = getchar()) != '\n' && c != EOF) {
input_buffer[i] = c;
i ++;
}
input_buffer[i] = '\0'; /* ensure that it's properly null-terminated */
I allocated a fixed-size buffer rather than using malloc, just for simplicity.
Also for simplicity, I've omitted any check that the input doesn't go past the end of the input buffer. If it does, the program may crash if you're lucky; if you're not lucky, it may just appear to work while clobbering memory that doesn't belong to you. It will work ok if the input line isn't too long. In any real-world program, you'll want to check for this.
BTW, what's being done here is more easily done using fgets() -- but it's good to learn how things work on a slightly lower level.