How can I make my input string S1 of the fgets (or similar statement) to be equal to my declared static string S2?
#include <stdio.h>
#include <string.h>
main() {
char s1[80];
char s2[] = "This is a test.";
int l1, l2;
system("clear");
printf("%s\n\n", s2);
printf("Please type exactly the above sentence: ");
fgets(s1,80,stdin);
l1=strlen(s1);
l2=strlen(s2);
printf("\n String entered for S1, have a length of %d:\n %s", l1, s1);
printf("\n String static for S2, have a legnth of %d:\n %s", l2, s2);
if(s1==s2)
printf("\n\nOk! they're with the same length!\n");
else
printf("\n\nNop! They are NOT the same.\n");
return(0);
}
You're doing a pointer comparison, not a string comparison. To compare the content of the strings, use strcmp (docs):
if (strcmp(s1, s2) == 0)
...
fgets reads a line of input (up to a specified length, in your case 80). It stores that line in the array pointed to by its first argument (s1) -- including the terminating '\n' newline character.
Which means that after your fgets call, assuming you typed exactly "This is a test." and then typed Enter, s1 will contain "This is a test.\n", not just "This is a test.".
You can remove that newline character before the comparison -- or rather you can replace it with a null character '\0', which marks the end of the string:
size_t len = strlen(s1);
if (s1[len-1] == '\n') {
s1[len-1] = '\0';
}
(You might need to move the declaration of len to the top of main if your compiler doesn't support mixed declarations and statements -- but the strlen call still has to be done after fgets.)
To test whether the s1 and s2 contain the same string value, use the strcmp function; your s1 == s2 does a pointer comparison. strcmp returns 0 if the strings are equal. (If they're not, it returns a negative or positive value to indicate whether the left string is lexicographically less than or greater than the right string.)
Some minor comments on your code:
main() should be int main(void). (Long story; for now, just take my word for it.)
There's probably no need to invoke system("clear"). Why do you want to clear the screen? There might be useful information on it. And it won't work on all systems. If I want to clear my screen before running your program, I can do it myself, thank you very much.
Your message "they're with the same length" isn't quite right. If you correct the test by using strcmp rather than ==, you're testing whether the strings have the same value, whether their lengths happen to be the same or not.
Usually when you print a message, it's best to put the newline \n at the end of the output. It's usually best to have just a single \n at the end of the message (unless you want to print multiple lines with one printf, or build up one line with multiple printfs, which you can do but it's not necessary here.)
Your question originally had gets and scanf tags. Never use the gets function; it's inherently unsafe and has been removed from the language. scanf is tricky, and not needed in this case.
Related
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
So I'm trying to make it so that you can write text into a file until you make a newline or type -1. My problem is that when you write, it just keeps going until it crashes and gives the error "Stack around the variable "inputChoice" was corrupted".
I believe the problem is that the program doesn't stop accepting stdin when you want to stop typing (-1, newline) and that causes the error. I've tried with a simple scanf and it works, but you can only write a word. No spaces and it doesn't support multiple lines either. That's why I have to use fgets
Judging from your comments, I assume that there are some basic concepts in C
that you haven't fully understood, yet.
C-Strings
A C-String is a sequence of bytes. This sequence must end with the value 0.
Every value in the sequence represents a character based on the
ASCII encoding, for example the
character 'a' is 97, 'b' is 98, etc. The character '\0' has
the value 0 and it's the character that determines the end of the string.
That's why you hear a lot that C-Strings are '\0'-terminated.
In C you use an array of chars (char string[], char string[SOME VALUE]) to
save a string. For a string of length n, you need an array of dimension n+1, because
you also need one space for the terminating '\0' character.
When dealing with strings, you always have to think about the proper type,
whether your are using an array or a pointer. A pointer
to char doesn't necessarily mean that you are dealing with a C-String!
Why am I telling you this? Because of:
char inputChoice = 0;
printf("Do you wish to save the Input? (Y/N)\n");
scanf("%s", &inputChoice);
I haven't changed much, got very demotivated after trying for a while.
I changed the %s to an %c at scanf(" %c, &inputChoice) and that
seems to have stopped the program from crashing.
which shows that haven't understood the difference between %s and %c.
The %c conversion specifier character tells scanf that it must match a single character and it expects a pointer to char.
man scanf
c
Matches a sequence of characters whose length is specified by the maximum field
width (default 1); the next pointer must be a
pointer to char, and there must be enough room for all the characters
(no terminating null byte is added). The usual skip of
leading white space is suppressed. To skip white space first, use an explicit space in the format.
Forget the bit about the length, it's not important right now.
The important part is in bold. For the format scanf("%c", the function
expects a pointer to char and its not going to write the terminating '\0'
character, it won't be a C-String. If you want to read one letter and one
letter only:
char c;
scanf("%c", &c);
// also possible, but only the first char
// will have a defined value
char c[10];
scanf("%c", c);
The first one is easy to understand. The second one is more interesting: Here
you have an array of char of dimension 10 (i.e it holds 10 chars). scanf
will match a single letter and write it on c[0]. However the result won't be
a C-String, you cannot pass it to puts nor to other functions that expect
C-Strings (like strcpy).
The %s conversion specifier character tells scanf that it must match a sequence of non-white-space characters
man scanf
s
Matches a sequence of non-white-space characters; the next pointer must be a
pointer to the initial element of a character array that is long enough to
hold the input sequence and the terminating null byte ('\0'), which is added
automatically.
Here the result will be that a C-String is saved. You also have to have enough
space to save the string:
char string[10];
scanf("%s", string);
If the strings matches 9 or less characters, everything will be fine, because
for a string of length 9 requires 10 spaces (never forget the terminating
'\0'). If the string matches more than 9 characters, you won't have enough
space in the buffer and a buffer overflow (accessing beyond the size) occurs.
This is an undefined behaviour and anything can happen: your program might
crash, your program might not crash but overwrites another variable and thus
scrwes the flow of your program, it could even kill a kitten somewhere, do
you really want to kill kittens?
So, do you see why your code is wrong?
char inputChoice = 0;
scanf("%s", &inputChoice);
inputChoice is a char variable, it can only hold 1 value.
&inputChoice gives you the address of the inputChoice variable, but the
char after that is out of bound, if you read/write it, you will have an
overflow, thus you kill a kitten. Even if you enter only 1 character, it will
write at least 2 bytes and because you it only has space for one character, a kitten will die.
So, let's talk about your code.
From the perspective of an user: Why would I want to enter lines of text, possibly a lot of lines of text
and then answer "No, I don't want to save the lines". It doesn't make sense to
me.
In my opinion you should first ask the user whether he/she wants to save the
input first, and then ask for the input. If the user doesn't want to save
anything, then there is no point in asking the user to enter anything at
all. But that's just my opinion.
If you really want to stick to your plan, then you have to save every line and
when the user ends entering data, you ask and you save the file.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFERLEN 1024
void printFile () {
int i;
char openFile[BUFFERLEN];
FILE *file;
printf("What file do you wish to write in?\n");
scanf("%s", openFile);
getchar();
file = fopen(openFile, "w");
if (file == NULL) {
printf("Could not open file.\n");
return;
}
// we save here all lines to be saved
char **lines = NULL;
int num_of_lines = 0;
char buffer[BUFFERLEN];
printf("Enter an empty line of -1 to end input\n");
// for simplicity, we assume that no line will be
// larger than BUFFERLEN - 1 chars
while(fgets(buffer, sizeof buffer, stdin))
{
// we should check if the last character is \n,
// if not, buffer was not large enough for the line
// or the stream closed. For simplicity, I will ignore
// these cases
int len = strlen(buffer);
if(buffer[len - 1] == '\n')
buffer[len - 1] = '\0';
if(strcmp(buffer, "") == 0 || strcmp(buffer, "-1") == 0)
break; // either an empty line or user entered "-1"
char *line = strdup(buffer);
if(line == NULL)
break; // if no more memory
// process all lines that already have been entered
char **tmp = realloc(lines, (num_of_lines+1) * sizeof *tmp);
if(tmp == NULL)
{
free(line);
break; // same reason as for strdup failing
}
lines = tmp;
lines[num_of_lines++] = line; // save the line and increase num_of_lines
}
char inputChoice = 0;
printf("Do you wish to save the Input? (Y/N)\n");
scanf("%c", &inputChoice);
getchar();
if (inputChoice == 'Y' || inputChoice == 'y') {
for(i = 0; i < num_of_lines; ++i)
fprintf(file, "%s\n", lines[i]); // writing every line
printf("Your file has been saved\n");
printf("Please press any key to continue");
getchar();
}
// closing FILE buffer
fclose(file);
// free memory
if(num_of_lines)
{
for(i = 0; i < num_of_lines; ++i)
free(lines[i]);
free(lines);
}
}
int main(void)
{
printFile();
return 0;
}
Remarks on the code
I used the same code as yours as the base for mine, so that you can spot the
differences much quicker.
I use the macro BUFFERLEN for declaring the length of the buffers. That's
my style.
Look at the fgets line:
fgets(buffer, sizeof buffer, stdin)
I use here sizeof buffer instead of 1024 or BUFFERLEN. Again, that's my
style, but I think doing this is better, because even if you change the size
of the buffer by changing the macro, or by using another explicit size, sizeof buffer
will always return the correct size. Be aware that this only works when
buffer is an array.
The function strdup returns a pointer a pointer to a new string that
duplicates the argument. It's used to create a new copy of a string. When
using this function, don't forget that you have to free the memory using
free(). strdup is not part of the standard library, it conforms
to SVr4, 4.3BSD, POSIX.1-2001. If you use Windows (I don't use Windows,
I'm not familiar with the Windows ecosystem), this function might not be
present. In that case you can write your own:
char *strdup(const char *s)
{
char *str = malloc(strlen(s) + 1);
if(str == NULL)
return NULL;
strcpy(str, s);
return str;
}
I'm trying to tokenize a phone number and split it into two arrays. It starts out in a string in the form of "(515) 555-5555". I'm looking to tokenize the area code, the first 3 digits, and the last 4 digits. The area code I would store in one array, and the other 7 digits in another one. Both arrays are to hold just the numbers themselves.
My code seems to work... sort of. The issue is when I print the two storage arrays, I find some quirks;
My array aCode; it stores the first 3 digits as I ask it to, but then it also prints some garbage values notched at the end. I walked through it in the debugger, and the array only stores what I'm asking it to store- the 515. So how come it's printing those garbage values? What gives?
My array aNum; I can append the tokens I need to the end of it, the only problem is I end up with an extra space at the front (which makes sense; I'm adding on to an empty array, ie adding on to empty space). I modify the code to only hold 7 variables just to mess around, I step into the debugger, and it tells me that the array holds and empty space and 6 of the digits I need- there's no room for the last one. Yet when I print it, the space AND all 7 digits are printed. How does that happen?
And how could I set up my strtok function so that it first copies the 3 digits before the "-", then appends to that the last 4 I need? All examples of tokenization I've seen utilize a while loop, which would mean I'd have to choose either strcat or strcpy to complete my task. I can set up an "if" statement to check for the size of the current token each time, but that seems too crude to me and I feel like there's a simpler method to this. Thanks all!
int main() {
char phoneNum[]= "(515) 555-5555";
char aCode[3];
char aNum[7];
char *numPtr;
numPtr = strtok(phoneNum, " ");
strncpy(aCode, &numPtr[1], 3);
printf("%s\n", aCode);
numPtr = strtok(&phoneNum[6], "-");
while (numPtr != NULL) {
strcat(aNum, numPtr);
numPtr = strtok(NULL, "-");
}
printf("%s", aNum);
}
I can primarily see two errors,
Being an array of 3 chars, aCode is not null-terminated here. Using it as an argument to %s format specifier in printf() invokes undefined behaviour. Same thing in a differrent way for aNum, too.
strcat() expects a null-terminated array for both the arguments. aNum is not null-terminated, when used for the first time, will result in UB, too. Always initialize your local variables.
Also, see other answers for a complete bug-free code.
The biggest problem in your code is undefined behavior: since you are reading a three-character constant into a three-character array, you have left no space for null terminator.
Since you are tokenizing a value in a very specific format of fixed length, you could get away with a very concise implementation that employs sscanf:
char *phoneNum = "(515) 555-5555";
char aCode[3+1];
char aNum[7+1];
sscanf(phoneNum, "(%3[0-9]) %3[0-9]-%4[0-9]", aCode, aNum, &aNum[3]);
printf("%s %s", aCode, aNum);
This solution passes the format (###) ###-#### directly to sscanf, and tells the function where each value needs to be placed. The only "trick" used above is passing &aNum[3] for the last argument, instructing sscanf to place data for the third segment into the same storage as the second segment, but starting at position 3.
Demo.
Your code has multiple issues
You allocate the wrong size for aCode, you should add 1 for the nul terminator byte and initialize the whole array to '\0' to ensure end of lines.
char aCode[4] = {'\0'};
You don't check if strtok() returns NULL.
numPtr = strtok(phoneNum, " ");
strncpy(aCode, &numPtr[1], 3);
Point 1, applies to aNum in strcat(aNum, numPtr) which will also fail because aNum is not yet initialized at the first call.
Subsequent calls to strtok() must have NULL as the first parameter, hence
numPtr = strtok(&phoneNum[6], "-");
is wrong, it should be
numPtr = strtok(NULL, "-");
Other answers have already mentioned the major issue, which is insufficient space in aCode and aNum for the terminating NUL character. The sscanf answer is also the cleanest for solving the problem, but given the restriction of using strtok, here's one possible solution to consider:
char phone_number[]= "(515) 555-1234";
char area[3+1] = "";
char digits[7+1] = "";
const char *separators = " (-)";
char *p = strtok(phone_number, separators);
if (p) {
int len = 0;
(void) snprintf(area, sizeof(area), "%s", p);
while (len < sizeof(digits) && (p = strtok(NULL, separators))) {
len += snprintf(digits + len, sizeof(digits) - len, "%s", p);
}
}
(void) printf("(%s) %s\n", area, digits);
I want to write a program that erases all characters in string 1 that appear in string 2 , using pointers .
This is what I did , but it did not work .
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
main()
{
char ch1[100] , ch2[100] ;
char *p1 , *p2;
printf("first chaine ");
gets(ch1);
printf("sd chaine");
gets(ch2);
for(p1=ch1;p1<ch1+100;p1++)
{
for(p2=ch2;p2<ch2;p2++)
{
if(*p1==*p2)
{
strcpy(p1,p1+1);
}
}
}
puts(ch1);
return 0 ;
}
strcpy() expects that its source and destination arguments don't overlap in memory — in other words, writing to the destination string shouldn't overwrite parts of the source string. So you can't use it to "shift" a string by an amount that's less than its length. Instead, you can use memmove(), which supports overlapping ranges.
You can replace your strcpy line with:
memmove(p1, p1+1, strlen(p1+1));
which will correctly do what you had expected the strcpy() call to do.
Also, your termination condition for the inner loop is p2<ch2, which is always false since they start out equal. You probably meant to write p2<ch2+100.
Your loop conditions have another problem, though: they go past the end of the actual string that's stored in the array. If the user types fewer than 99 characters of input for either string, the corresponding array will contain garbage characters after the null terminator. In the ch1 array, scanning past the end of the string may cause strlen() to go past the end of the whole array looking for another null terminator, and in ch2, going past the end of the string will cause the program to filter out characters that the user didn't specify.
You should change the two loop conditions to *p1 != '\0' and *p2 != '\0'. This will make the loops stop when they reach the end of the two strings.
NEVER USE GETS()
It's unsafe to use gets() under any circumstances, because it doesn't check the length of its input against the length of the array. Use fgets() instead.
Now that you understand that, take a look at your inner loop:
for(p2=ch2;p2<ch2;p2++)
You set p2=ch2, then check if p2<ch2. This will always be false. Perhaps you mean to check if p2<ch2+100?
First of all, you need bounds checking. gets() does not provide bounds checking.
As for for your loops, you will never enter the nested loops:
for(p2=ch2;p2<ch2;p2++)
Your initialization will always make your condition false, and you will never enter the loop.
Here is one solution to the problem. This code eliminates the inner loop of the question code by implementing strchr() to determine if a specific character of string1 is present in string2:
#include <stdio.h>
#include <string.h>
int main(void)
{
char ch1[100] , ch2[100];
char *p1, *p2;
/* Get string1 from stdin. */
printf("first chaine ");
fgets(ch1, sizeof(ch1), stdin);
/* Get string2 from stdin. */
printf("sd chaine ");
fgets(ch2, sizeof(ch2), stdin);
/* Eliminate all chars from string1 that appear in string2. */
for(p1=ch1, p2=ch1; *p1; p1++)
{
if(strchr(ch2, *p1))
continue;
*p2++ = *p1;
}
*p2 = '\0';
/* Print modified string1. */
puts(ch1);
return(0);
}
Execution example of the above code:
SLES11SP2:~/SO> ./test
first chaine Now is the time for all good men to come to the aid of their country.
sd chaine aeiou
Nw s th tm fr ll gd mn t cm t th d f thr cntry.
SLES11SP2:~/SO>
This is my target:
input: string with mixed ASCII characters (uppercase, lowercase, numbers, spaces)
output: string with only uppercase characters
I have this:
#include <stdio.h>
void csere(char s[]){
int i;
for(i=0; s[i]!='\0'; i++){
if('a'<=s[i] && s[i]<='z'){
s[i]-=32;
}
printf("%c", s[i]);
}
}
void main(){
char s[1];
scanf("%s", &s);
csere(s);
}
My problem is:
The function stops at the first 'space' character in the string.
I tried to change the s[i] != '\0' in the 'for' part for i <
strlen(s) or just for s[i], but I still get the same result.
Example: qwerty --> QWERTY, but qwe rty --> QWE
(smaller problem: The program only accepts strings with length less than 12, if i change the 1 to 0 in main function.)
Thanks for help. Sorry for bad English.
scanf only scans non-whitespace characters with the %s modifier. If you want to read everything on a string you should use fgets with stdin as the third parameter:
fgets(s, sizeof s, stdin);
If you really need to use scanf for homework or something, you should use something like:
scanf("%128[^\n]", s);
Also, take note you are not allocating enough space for the string, the fact that it has not crashed is just pure coincidence... you should allocate the space on your array:
char s[128]; // change 128 for max string size
Actually, the fgets() usage I wrote earlier would only read 1 character (including the terminator string) since you only put 1 character on the array... change the array size and it should work.
You could also just use toupper() on ctype.h, but I guess this is some kind of homework or practice.
Furthermore, if you are allowed to use pointers, this would be a shorter (and probably more performant although that'd have to be tested... compilers are good these days :-) ) way to convert to uppercase (notice though it changes your original char array, and doesn't print it, although that'd be easy to modify/add, I'll leave it to you):
void strupper(char *sptr) {
while (*sptr) {
if ((*sptr >= 'a' ) && (*sptr <= 'z')) *sptr -= 32;
sptr++;
}
}
From scanf
s
Matches a sequence of bytes that are not white-space characters. The application shall ensure that the corresponding argument is a pointer to the initial byte of an array of char, signed char, or unsigned char large enough to accept the sequence and a terminating null character code, which shall be added automatically.
This means, with %s, scanf reads a string until it encounters the first white space character. Therefore, your function converts the given string only to the first space.
To the second (smaller) problem, the array s must be large enough for the entire string given. Otherwise, you overwrite the stack space and get undefined behaviour. If you expect larger strings, you must increase the size of s, e.g.
char s[100];
I have a string I composed using memcpy() that (when expanded) looks like this:
char* str = "AAAA\x00\x00\x00...\x11\x11\x11\x11\x00\x00...";
I would like to print every character in the string, and if the character is null, print out "(null)" as a substitute for '\0'.
If I use a function like puts() or printf() it will just end at the first null and print out
AAAA
So how can I get it to print out the actual word "(null)" without it interpreting it as the end of the string?
You have to do that mapping yourself. If you want to, that is. In C, strings are null-terminated. So, if you use a formatted output function such as printf or puts and ask it to print a string (via the format specifier %s) it'd stop printing str as soon as it hits the first null. There is no null word in C. If you know exactly how many characters you have in str you might as well loop over them and print the characters out individually, substituting the 0 by your chosen mnemonic.
The draft says 7.21.6.1/8:
p The argument shall be a pointer to void. The value of the pointer is
converted to a sequence of printing characters, in an
implementation-defined manner.
However, the following:
$ cat null.c
#include <stdio.h>
int main() {
printf("%p\n", (void *)0);
}
produces:
00000000
on both gcc 4.6 and clang 3.2.
However, on digging deeper:
$ cat null.c
#include <stdio.h>
int main() {
printf("%s\n", (void *)0);
}
does indeed produce the desired output:
(null)
on both gcc and clang.
Note that the standard does not mandate this:
s If no l length modifier is present, the argument shall be a pointer
to the initial element of an array of character type.280) Characters
from the array are written up to (but not including) the terminating
null character. If the precision is specified, no more than that many
bytes are written. If the precision is not specified or is greater
than the size of the array, the array shall contain a null character.
Relying on this behavior may lead to surprises!
Instead of printing the string with %s , you will have to come up with a for loop that checks a condition whther a given char in your char array is a \0 and then print the NULL
From C++ Reference on puts() (emphasis mine):
Writes the C string pointed by str to stdout and appends a newline
character ('\n'). The function begins copying from the address
specified (str) until it reaches the terminating null character
('\0'). This final null-character is not copied to stdout.
To process data such as you have, you'll need to know the length. From there, you can simply loop across the characters:
/* ugly example */
char* str = "AAAA\x00\x00\x00...\x11\x11\x11\x11\x00\x00...";
int len = ...; /* get the len somehow or know ahead of time */
for(int i = 0; i < len; ++i) {
if('\0' == str[i]) {
printf(" (null) ");
} else {
printf(" %c ", str[i]);
}
}
One of the key cornerstones of C is strings are terminated by '\0'. Everyone lives by that rule. so I suggest you not think of your string as a string but as an array of characters.
If you traverse the array and test for '\0', you can print "(null)" out in place of the character. Here is an example. Please note, your char * str was created either as a char array or on the stack using malloc. This code needs to know the actual buffer size.
char* str = "AAAA\x00\x00\x00...\x11\x11\x11\x11\x00\x00...";
int iStrSz = <str's actual buffer size>
int idx;
for(idx=0; idx<iStrSz; idx++)
{
if('\0' == *(str + idx)
{
sprintf("%s", "(null)");
}
else
{
putchar(*(str + idx));
}
}
printf("%s", "\n");