I am having a problem with loop, I don't know why but loop never ends.
int main(int argc, char *argv[])
{
int j;
char s[2];
for(j=1;j<=3;j++)
{
sprintf(s,"s%d",j);
printf("%s", s);
}
system("PAUSE");
return 0;
}
I think loop should show s1s2s3 in console.
char s[2]; should be char s[3];, or else you will get a buffer overflow.
Abhineet explains why the change is necessary. However, in order to corroborate his answer, here is the relevant section from the standard.
7.19.6.6
The sprintf function is equivalent to fprintf, except that the output
is written into an array (specified by the argument s) rather than to a
stream. A null character is written at the end of the characters
written; it is not counted as part of the returned value. If copying
takes place between objects that overlap, the behavior is undefined.
From the documentation,
The size of the buffer should be large enough to contain the entire resulting string.
You are already pushing two chars to s, so, there is not enough space for appending \0. This will cause undefined behavior. The solution is to provide one extra char memory to append \0.
char s[2]; to char s[3];
I know I have replied pretty late but couldn't stop myself from explaining the OP, "why he has to use s[3] instead of s[2] ?"
Related
This problem is blowing my mind...Can anyone please sort out the problem because i have already wasted hours on this.. ;(
#include <stdio.h>
#include <string.h>
int main(){
char string[] = "Iam pretty much big string.";
char temp1[50];
char temp2[10];
// strcpy() and strncpy()
strcpy(temp1, string);
printf("%s\n", temp1);
strncpy(temp2, temp1, 10);
printf("%s\n", temp2);
return 0;
}
Result
Iam pretty much big string.
Iam prettyIam pretty much big string.
Expected Result:
Iam pretty much big string.
Iam pretty
The strncpy function is respecting the 10 byte limit you're giving it.
It copies the first 10 bytes from string to temp2. None of those 10 bytes is a null byte, and the size of temp2 is 10, so there are no null bytes in temp2. When you then pass temp2 to printf, it reads past the end of the array invoking undefined behavior.
You would need to set the size given to strncpy to the array size - 1, then manually add the null byte to the end.
strncpy(temp2, temp1, sizeof(temp2)-1);
temp2[sizeof(temp2)-1] = 0;
The address of temp2 is just before the address of temp1 and because you do not copy the final 0, the printf will continue printing after the end of temp2.
As time as you do not insert the 0, the result of printf is undefined.
You invoke Undefined Behavior attempting to print temp2 as temp2 is not nul-terminated. From man strncpy:
"Warning: If there is no null byte among the first n bytes of src,
the string placed in dest will not be null-terminated." (emphasis in
original)
See also C11 Standard - 7.24.2.4 The strncpy function (specifically footnote: 308)
So temp2 is not nul-terminated.
Citation of the appropriate [strncpy] tag on Stack Overflow https://stackoverflow.com/tags/strncpy/info, which may help you to understand what happens exactly:
This function is not recommended to use for any purpose, neither in C nor C++. It was never intended to be a "safe version of strcpy" but is often misused for such purposes. It is in fact considered to be much more dangerous than strcpy, since the null termination mechanism of strncpy is not intuitive and therefore often misunderstood. This is because of the following behavior specified by ISO 9899:2011 7.24.2.4:
char *strncpy(char * restrict s1,
const char * restrict s2,
size_t n);
/--/
3 If the array pointed to by s2 is a string that is shorter than n characters, null characters
are appended to the copy in the array pointed to by s1, until n characters in all have been
written.
A very common mistake is to pass an s2 which is exactly as many characters as the n parameter, in which case s1 will not get null terminated. That is: strncpy(dst, src, strlen(src));
/* MCVE of incorrect use of strncpy */
#include <string.h>
#include <stdio.h>
int main (void)
{
const char* STR = "hello";
char buf[] = "halt and catch fire";
strncpy(buf, STR, strlen(STR));
puts(buf); // prints "helloand catch fire"
return 0;
}
Recommended practice in C is to check the buffer size in advance and then use strcpy(), alternatively memcpy().
Recommended practice in C++ is to use std::string instead.
From the manpage for strncpy():
Warning: If there is no null byte among the first n bytes of src, the string placed in dest will not be null-terminated.
Either your input is shorter than the supplied length, you add the terminating null byte yourself, or it won't be there. printf() expects the string to be properly null terminated, and thus overruns your allocated buffer.
This only goes to show that the n variants of many standard functions are by no means safe. You must read their respective man pages, and specifically look for what they do when the supplied length does not suffice.
i'm trying to get and print a string with gets and puts but i get a segmentation fault error when i use them togheter.
this is the code i'm trying to get this working. [i type the string "prova" to test it]
int main()
{
char *s;
gets(s);
puts(s);
return 0;
}
if i change "gets" with "scanf" i get the same error.
if i change "puts" with "printf("%s", s)" i get the output.
if i declare char *s = "prova" and then puts(s) i get the output.
i also tried to change char *s; with char s[] but i get the same error.
where i'm i wrong on this? ty very much
i know gets is bad, is just bc i'm writing exercise from "C how to program, fifth edition" by Deitel and Deitel
You have multiple problems with that piece of code. To start with gets have been deprecated since the C99 standard, and in the C11 standard it has been removed. The reason is that it's not very safe, and has no bounds-checking and so can write beyond the bounds of the memory you pass to it leading to buffer overflows.
Secondly, you use the uninitialized local variable s. The value of an uninitialized variable is indeterminate, and will be seemingly random. Using an uninitialized local variable leads to undefined behavior, which often leads to crashes.
Another problem is if you initialize s to point to a literal strings. Literals strings are constant (read-only) arrays of characters, and attempting to write to it will again lead to undefined behavior.
You need to allocate some room for the string:
char s[256];
gets(s);
puts(s);
But gets is bad. (It doesn't know how big your buffer is, so what happens if more than 255 characters are read?)
The most important mistake you have is that you are declaring a char pointer, but you are not reserving the space in memory where the characters will be stored, so you got a pointer that point to some random memory adress that you should'nt use. the "right" thing to do will be:
#include <stdio.h>
#include <stdlib.h>
#define LENGHT 20
int main()
{
char *s;
s=malloc(sizeof(char)*LENGHT); //here you make the pointer point to a memory adress that you can use
gets(s);
puts(s);
free (s);
return 0;
}
But also is strongly recommend to avoid using gets because that function doesn't check for the length of the input, so use fgets instead that allow you to do that, you will only need to set the data stream to stdin.
The code will be:
#include <stdio.h>
#include <stdlib.h>
#define LENGHT 20
int main()
{
char *s;
s=malloc(sizeof(char)*LENGHT);
fgets(s,20,stdin);
puts(s);
free(s);
return 0;
}
I was making a basic program of strings and did this. There is a string in this way:
#include<stdio.h>
int main()
{
char str[7]="network";
printf("%s",str);
return 0;
}
It prints network.In my view, it should not print network. Some garbage value should be printed because '\0' does not end this character array. So how it got printed? There were no warning or errors too.
That's because
char str[7]="network";
is the same as
char str[7]={'n','e','t','w','o','r','k'};
str is a valid char array, but not a string, because it's no null-terminated. So it's undefined behavior to use %s to print it.
Reference: C FAQ: Is char a[3] = "abc"; legal? What does it mean?
char str[7]="network";
This Invokes Undefined behavior.
You did not declared array with enough space
This should be
char str[8]="network";
char str[7]="network";
you did not provide enough space for the string
char str[8]="network";
It's possible that stack pages start off completely zeroed in your system, so the string is actually null-terminated in memory, but not thanks to your code.
Try looking at the program in memory using a debugger, reading your platform documentation or printing out the contents of str[7] to get some clues. Doing so invokes undefined behavior but it's irrelevant when you're trying to figure out what your specific compiler and OS are doing at one given point in time.
I want a user defined function which is equivalent to strlen() function in C. In the below program it does the same function as strlen() but it has a limit to it. How can I make it count any length of text.
#include <stdio.h>
#include <conio.h>
void main()
{
int len(char *);
char s[20];
int l;
printf("Enter a string: ");
gets(s);
l=len(s);
printf("length of string is =%d",l);
getch();
}
int len(char *t)
{
int count=0;
while(*t!='\0')
{
count++;
t++;
}
return(count);
}
I think your "limit" is because you use gets() on a buffer of 20 bytes. You will experience issues due to a buffer overflow. Exactly what happens when you do that is not entirely predictable.
If you fix that, I think your function will work as you expect it to. (Read the other people's answers for insight on your length function.)
If you truly want "any length", you'll need an arbitrary-precision integer library (such as libgmp) for the counter. That's pretty unreasonable, though, since the string will have to fit into your memory, and each character actually has to have an address. That is to say, the length of any string that fits into addressable space can be expressed in a variable of type size_t (or unsigned long int, I suppose; it'll be something of the same size as the machine's register size).
(Please don't ask about how to form the one-past-the-end pointer of a string that fills out the entire addressable memory.)
Its limit is int bounds. if you increase it, use long. Also, make it unsigned to double the maximum. If you want to be sure that it fit, use size_t (which original strlen use)
BTW, never use gets.
What's the limit you want? Historically a string is terminated by '\0' because its the only way to know where the string ends, otherwise you could actually read the whole stack or heap way past the true length of the string. A method used by other functions to identify the end of a string, to prevent crash not as a feature is to stop reading when a value outside the charset is found.
Edit:
Obviously I misunderstood the question.
int main(){
int Length = 0;
char StrArray[10] = "Hello";
while (StrArray[Length] != '\0')
{
StrArray[Length];
Length++;
}
std::cout << Length;
std::cin.get();
}
consider the following code:
t[7] = "Hellow\0";
s[3] = "Dad";
//now copy t to s using the following strcpy function:
void strcpy(char *s, char *t) {
int i = 0;
while ((s[i] = t[i]) != '\0')
i++;
}
the above code is taken from "The C programming Language book".
my question is - we are copying 7 bytes to what was declared as 3 bytes.
how do I know that after copying, other data that was after s[] in the memory
wasn't deleted?
and one more question please: char *s is identical to char* s?
Thank you !
As you correctly point out, passing s[3] as the first argument is going to overwrite some memory that could well be used by something else. At best your program will crash right there and then; at worst, it will carry on running, damaged, and eventually end up corrupting something it was supposed to handle.
The intended way to do this in C is to never pass an array shorter than required.
By the way, it looks like you've swapped s and t; what was meant was probably this:
void strcpy(char *t, char *s) {
int i = 0;
while ((t[i] = s[i]) != '\0')
i++;
}
You can now copy s[4] into t[7] using this amended strcpy routine:
char t[] = "Hellow";
char s[] = "Dad";
strcpy(t, s);
(edit: the length of s is now fixed)
About the first question.
If you're lucky your program will crash.
If you are not it will keep on running and overwrite memory areas that shouldn't be touched (as you don't know what's actually in there). This would be a hell to debug...
About the second question.
Both char* s and char *s do the same thing. It's just a matter of style.
That is, char* s could be interpreted as "s is of type char pointer" while char *s could be interpreted as "s is a pointer to a char". But really, syntactically it's the same.
That example does nothing, you're not invoking strcpy yet. But if you did this:
strcpy(s,t);
It would be wrong in several ways:
The string s is not null terminated. In C the only way strcpy can know where a string ends is by finding the '\0'. The function may think that s is infinite and it might corrupt your memory and make the program crash.
Even if was null terminated, as you said the size of s is only 3. Because of the same cause, strcpy would write memory beyond where s ends, with maybe catastrophic results.
The workaround for this in C is the function strncpy(dst, src, max) in which you specify the maximum number of chars to copy. Still beware that this function might generate a not null terminated string if src is shorter than max chars.
I will assume that both s and t (above the function definition) are arrays of char.
how do I know that after copying, other data that was after s[] in the memory wasn't deleted?
No, this is worse, you are invoking undefined behavior and we know this because the standard says so. All you are allowed to do after the three elements in s is compare. Assignment is a strict no-no. Advance further, and you're not even allowed to compare.
and one more question please: char s is identical to char s?
In most cases it is a matter of style where you stick your asterix except if you are going to declare/define more than one, in which case you need to stick one to every variable you are going to name (as a pointer).
a string-literal "Hellow\0" is equal to "Hellow"
if you define
t[7] = "Hellow";
s[7] = "Dad";
your example is defined and crashes not.