How to properly terminate strings in C programming? [closed] - c

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 3 years ago.
Improve this question
I'm using scanf to scan 5 product names and store them in a string. However, when i print them, the last one is always printed as ♣. Where am i going wrong ?
I am trying to take in the id, name and prices of 5 products and print them using structures. However the last product name is always printed as ♣. I realised that this may be due to improper terminating of the string, and tried the solutions provided to such questions.
I saw another similar question on strings and tried to terminate the string properly by doing, char name[50]={'0'}; in my code. This part is within the structure part of the code.
struct product
{
int id;
char name[50];
int price;
};
void main()
{
struct product p [5];
int i,a;
for(i=1;i<=5;i++)
{
printf("Enter the id no., name and price of the product %d\n",i);
scanf("%d%s%d",&p[i].id,&p[i].name,&p[i].price);
}
printf("The id no., name and price of the product %d are\n",i);
for(i=1;i<=5;i++)
{
printf("\t%d\t%s/0\t%d\n",p[i].id,p[i].name,p[i].price);
}
}
The final output, that is p[5].name ,should've been what i had entered, but is, however, ♣.
And if i try to terminate the code by entering: char name[50]={'\0'};
it puts up an error message over the '=' saying that it expected a ';'.

The problem is not with termination of strings. [Note 1]
Your problem is that arrays in C start at index 0, not index 1. So the elements in p are p[0] through p[4] and so p[5] references random memory. C does not check that array indexes are valid, and using invalid ones leads to odd bugs like this one.
scanf certainly NUL-terminates strings, which is why I said that termination is not a problem. However, it doesn't know how much memory you've reserved for the string, so it could well overwrite random memory if the string entered by the user is too long. Better to use the format "%d%49s%d" (in this case) to limit the string read to 49 characters. (You can't fit a 50-character string in a 50-element array precisely because you need to leave space for the terminating NUL.)
However, you also need to check the return value of scanf. That function returns the number of successful conversions, which in this case must be three. If it returns a smaller number, that means one of the conversions failed, and if a numeric conversion fails, the offending character (perhaps a letter) will still be the next input character, so the next %d conversion will also fail.
Notes:
If you want to store a NUL in a string, you would do something like;this, assuming you know where the string ends:
p[i].name[len] = `\0`;
You can declare and initialise a character array so that all its elements are 0:
char name[50] = { '\0' };
But you can't put an initialiser inside the definition of a struct. The struct declaration only defines the general form of a composite object; it doesn't declare any instances of that object so there is nothing to initialise.

Looks great. Remember that arrays start from 0. Change for loops to indexes 0 - 4.
for(i = 0; i < 5; i++)
{
printf("Enter the id no., name and price of the product %d\n",i);
scanf("%d%s%d",&p[i].id,&p[i].name,&p[i].price);
}
In general, I highly recommend using fgets for input of strings from user in order to avoid the risks of scanf + adds the NULL at end.
#include <string.h>
for(i = 0; i < 5; i++)
{
printf("Enter the id no., name and price of the product %d\n",i);
scanf("%d",&p[i].id);
fgets(p[i].name, 50, stdin);
scanf("%d",&p[i].price);
}
More about fgets -> https://www.geeksforgeeks.org/fgets-gets-c-language/

Related

Why is a strange character appearing on my screen? [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 9 months ago.
Improve this question
I am new to C, I have written a very simple program to get the first name and surname, here is my code...
#include <stdio.h>
#include <conio.h>
int main(){
int num,bankpin;
char fn[20],sn[20];
printf("Welcome to authorization. We ill now begin the process");
printf("\nFirst, please enter your first name: ");
scanf(" %s",fn);
printf("\nEnter your surname: ");
scanf(" %s",sn);
printf("\nWelcome to the system %c %c",&fn,&sn);
return 0;
}
Welcome to authorization. We ill now begin the process
First, please enter your first name: A
Enter your surname: A
Welcome to the system α
Why is this strange "a" appearing on my screen instead of "A A"?
In fact it appears on my screen even if I try a different combination of letters
I have even tried recompiling the code
I'm guessing this is because you are trying to print &fn, which is a pointer, as char. You're basically telling the program to interpret the address o as a symbol code.
Try changing the
printf("\nWelcome to the system %c %c",&fn,&sn) to
printf("\nWelcome to the system %s %s",fn,sn)
Short answer
You are sending the array pointer's address as an argument, and telling printf to interpret it as a single char, resulting in undefined behavior. The fix is to replace the line
printf("\nWelcome to the system %c %c",&fn,&sn);
with
printf("\nWelcome to the system %s %s",fn,sn);
Long answer
The weird character is due to your code reading an unintended value, and trying to interpret it. If you run your code a few times, you will find that you don't always get this symbol, but many other ones, including nothing at all (seemingly). What is going here ?
The short answer is that you are misinforming the printf function by giving her a false symbol and a false value. Let's look at a similar example :
char myString[20] = "Hello!";
printf("%c", &myString);
In this snippet we create an array of characters, which actually means creating a pointer of char* type, and allocating its size (here to 20). Pointers are often confusing when starting with C, but they are in principle pretty simple : they are simply variables that, instead of containing a value, contain an address. Since arrays in C store their value sequentially, that is one after the other, it makes quite a lot of sense to have them be pointers : if you know where the array starts, and that its members are spaced evenly, it makes it quite easy to go over the array.
So since your array is a pointer, reading it directly will print something along the lines of "0x7ffc5a6dbb70". Putting '&' before it gives a very similar result : this operator consists in asking for the address of a variable, which is then in your code transmitted to the printf as an argument.
This doesn't make any sense there : a char is, in C, behind the scene, actually an integer variable with very small capacity, from 0 to 255 to be precise. For example the two lines in the following snippet produce the same result :
printf("%c", 'a');
printf("%c", 97);
Now you see what is happening in the original printf : the function is expecting to receive a very small integer to convert to one character, and instead receives an address, which is the reason why the output is so weird. Since addresses change basically at every run of the code, that is also the reason why the output changes very often.
You thus need to adapt the information in the printf function. First, inform that you wish to print a char array with the symbol "%s". This will make the function expect to receive a pointer to the first element of a char array, which it will then iterate over. Thus, as argument, you need to send this pointer, that you directly have in the form of the myString variable.
Thus running
char myString[20] = "Hello!";
printf("%s", myString);
prints 'Hello!', as expected :)
The funcion scanf is a little tricky, please delete the leading space, inside quotes only include what are you expecting to receive, ever.
scanf("%s",fn);
The printf function needs %s, same as scanf, to deal with string, later you don't need the & operator in this case.
printf("\nWelcome to the system %s %s",fn,sn);

Difference between gets() and scanf("%s") [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I declared a character pointer, and used it for to scan a string in runtime; I don't know the number of characters that I'm going to enter, so I didn't use calloc or malloc. The program ends when it reached the line scanf("%s", NewMsg_au8).
I'm using CodeBlocks 17.12 editor.
I tried hard coding one of the input case like, NewMsg_au8="0123456789ABCDEF"; — that works fine.
uint8 * NewMsg_au8;
scanf("%s",NewMsg_au8);//<==
printf("Your entered message is: %s\n",NewMsg_au8);
return NewMsg_au8;
gets(s) and scanf("%s", s) are both unsafe and potentially incorrect because:
with those calls as shown, there is no way for either function to determine the maximum number of characters to store into the array pointed to by s, hence overlong input will cause a buffer overrun leading to undefined behavior.
in your case, it is even worse as s is an uninitialized pointer, so both functions would try a store data into a random address in memory causing undefined behavior in all cases.
gets() cannot be used safely and has been deprecated in and then removed from the C Standard.
However, scanf() can be given a limit with a numeric value between % and s:
#include <stdio.h>
#include <string.h>
char *read_string(void) {
char buf[100];
if (scanf("%99s", buf) == 1) {
printf("Your entered message is: %s\n", buf);
return strdup(buf); /* return an allocated copy of the input string */
} else {
/* no input, probably at end of file */
return NULL;
}
}
Note how only 99 characters can be stored into the array buf to allow for the null byte terminator that marks the end of a C string. The %99s conversion specification lets scanf() store at most 100 bytes into buf, including the '\0' terminator.
That is a typical beginners error. You do not save data in pointers (with gets() or scanf()) but in buffers.
Therefore, you have 2 solutions:
Use an array big enough to hold the data. You have to decide yourself what "big enough" means, according to the details of your application.
Use a pointer, and then allocate memory with malloc() - the size, again, you have to decide it. Do not forget to deallocate the memory when you no longer need it.
I tried hard coding one of the input case like, NewMsg_au8="0123456789ABCDEF"; — that works fine.
That is normal, because in that case the compiler automatically allocates enough memory to hold the string.
Please always remember when working with strings: you always need to allocate an extra byte for the terminating null character - the mark of the end of the string. Otherwise, you will need to ask questions again :)

please tell me why does the output of the two picture is different? [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
This program accept 5 string and print them.
here is the program:-
#include"stdio.h"
#include"conio.h"
void main(){
clrscr();
char s[5];
for(int i=0;i<5;i++){
scanf("%s", s[i]);
}
for(i=0;i<5;i++){
printf("\n\n%s", s[i]);
}
getch();
}
when i execute this program the output will be this
Click here to see the output of the program
but when i enter the string in different way it print wrong output
Click here to see the output of the program
You are reading a string into a char, or rather, the string you read starts at the char position i in s. As s is very short (and when i is 5 it is empty), there will be an overflow, causing undefined behavior.
You want to have an array of strings, not of chars, as Blue Pixy mentions in his comment, e.g. char s[5][32];.
Also turn warnings on. The i in the second for loop is not defined.
You've declared s as a 5-element array of char; each s[i] can store a single character value, not a string. Since you don't explicitly initialize each s[i], they contain an indeterminate value.
The argument corresponding to the %s specifier in scanf must have type char * (each s[i] has type char), and it must point to the first element of an array of char large enough to store the string contents (including the 0 terminator that marks the end of the string).
When you call
scanf( "%s", s[i] );
you're telling scanf to store the next sequence of non-whitespace characters to the address corresponding to the value stored in s[i], which is a) indeterminate and b) likely not valid. The resulting behavior is undefined, meaning pretty much anything can happen - your code may work as expected, it may crash outright, it may give you garbled output, it may corrupt other data, etc.
As written, s can store a string up to 4 characters long.
If you want to store an array of strings, then s needs to be a 2-dimensional array of char:
#define MAX_STRING_LENGTH 20 // or however long you expect your longest string to be
...
char s[5][MAX_STRING_LENGTH + 1];
Each s[i] can now store a string up to MAX_STRING_LENGTH characters. The rest of your code should now behave as expected.

Unusual character when writing to file [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 6 years ago.
Improve this question
I've created a struct with 2 char[] and one int. I created an array of this struct and scanfed several inputs to store data into the array. Then I used fprintf to write this data to the file. But when I open the file I get û before every new record. Idk why is it happening.
Here's the relevant code:
FILE *outputFile=fopen("1021.txt","ab");
int tickets=0,i=1;
struct air s[30];
printf("\nEnter Number of tickets:");
scanf("%d",&tickets);
for (i=1;i<=tickets;i++)
{
printf("\nEnter the name\t");
scanf("%s",&s[i].name);
printf("\nEnter the phone number\t");
scanf("%s",&s[i].phoneNo);
printf("\n Enter the address\t");
scanf("%s",&s[i].address);
printf("Your ticket is confirmed\t");
getch();
}
for (i=0;i<=tickets;i++)
{
printf("%s", s[i].name);
printf("%s", s[i].phoneNo);
printf("%s", s[i].address);
fprintf(outputFile,"%s",s[i].name);
fprintf(outputFile,"%s",s[i].phoneNo);
fprintf(outputFile,"%s",s[i].address);
}
Here's what I get in the file:
ûdalla03332228458dallaÈfsÇûÿÿÿÿàrancho03312041265dallabancho
Where are those unusual characters coming from?
Your input loop is
for (i=1;i<=tickets;i++)
but the output loop is
for (i=0;i<=tickets;i++)
So you are writing data to file from element [0] that you have no data entered for. That is why it is junk.
In C, arrays are indexed from [0], and neither of those loops is right. Please change both of them to
for (i = 0; i < tickets; i++)
There are other problems in the code too, but this addresses the immediate "uninitialised data" problem.
Edit: some other problems.
You opened the file in "binary" mode, but you are using it as a text file. I believe the distinction is only necessary in Windows.
FILE *outputFile=fopen("1021.txt", "at"); // change to "t"
The string address passed to scanf should not contain an & address-of (unlike an int). Just pass the array - it decays to the required pointer.
scanf("%s", s[i].name); // removed `&`
As you have not written any newline to file to demark your string data, when you read the data back in, you will not know where each ends and the next begins. So for example, add the newline like this
fprintf(outputFile, "%s\n", s[i].name); // added \n
You say one member is an int presumably the phone number, but you are inputting as a string. Yet it is a bad idea to store phone numbers as integers, because a) thay might contain a character such as '+' or b) may start with a leading 0 and that will be lost when you store as int. So change the struct member phoneNo to be a char array of adequate length.
The scanf format specifier %s will stop at the first whitespace it meets, so the input statements will be better as this, which will only stop when it finds a newline or hits the length limit:
int res = scanf("%29[^\n]", s[i].name);
where the array length defined was [30] (you did not show the struct). Alternatively you could research the use of fgets().
Finally, you should check the return value of the functions you are calling to see if they were successful. fopen will tell you if the file opened correctly. scanf will tell you the number of entries it scanned, and fgets tells you if it was successful too.

Dynamic memory allocation for input? [closed]

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 9 years ago.
Improve this question
I am having a lot of trouble starting my project. Here are the directions:
"Complete counts.c as follows:
Read characters from standard input until EOF (the end-of-file mark) is read. Do not prompt the user to enter text - just read data as soon as the program starts.
Keep a running count of each different character encountered in the input, and keep count of the total number of characters input (excluding EOF)."
The format my professor gave me to start is: `
#include <stdio.h>
int main(int argc, char *argv[]) {
return 0;
}
In addition to how to start the problem, I'm also confused as to why the two parameter's are given in the main function when nothing is going to be passed to it. Help would be much appretiated! Thank you!
`
Slightly tricky to see what you're having trouble with here. The title doesn't form a complete question, nor is there one in the body; and they seem to be hinting at entirely different questions.
The assignment tells you to read characters - not store them. You could have a loop that only reads them one at a time if you wish (for instance, using getchar). You're also asked to report counts of each character, which would make sense to store in an array. Given that this is of "each different character", the simplest way would be to size the array for all possible characters (limits.h defines UCHAR_MAX, which would help with this). Remember to initialize the array if it's automatically allocated (the default for function local variables).
Regarding the arguments to main, this program does not need them, and the C standard does allow you to leave them out. They're likely included as this is a template of a basic C program, to make it usable if command line arguments will be used also.
For more reference code you might want to compare the word count utility (wc); the character counting you want is the basis of a frequency analysis or histogram.
This should give you a start to investigate what you need to learn to complete your task,
Initially declare a character input buffer of sufficient size to read chars as,
char input[SIZE];
Use fgets() to read the characters from stdin as,
if (fgets(input, sizeof input, stdin) == NULL) {
; // handle EOF
}
Now input array has your string of characters which you to find occurrence of characters. I did not understand When you say different characters to count, however you have an array to traverse it completely to count the characters you need.
Firstly, luckily for you we will not need dynamic memory allocation at all here as we are not asked to store the input strings, instead we simply need to record how many of each ascii code is input during program run, as there a constant and finite number of those we can simply store them in a fixed size array.
The functions we are looking at here (assuming we are using standard libs) are as follows:
getchar, to read chars from standard input
printf, to print the outputs back to stdout
The constructs we will need are:
do {} while, to loop around until a condition is false
The rest just needs simple mathematical operators, here is a short example which basically shows a sample solution:
#include <stdio.h>
int main(int argc, char *argv[])
{
/* Create an array with entries for each char,
* then init it to zeros */
int AsciiCounts[256] = {0};
int ReadChar;
int TotalChars = 0;
int Iterator = 0;
do
{
/* Read a char from stdin */
ReadChar = getchar();
/* Increment the entry for its code in the array */
AsciiCounts[ReadChar]++;
TotalChars++;
} while (ReadChar != EOF);
/* Stop if we read an EOF */
do
{
/* Print each char code and how many times it occurred */
printf("Char code %#x occurred %d times\n", Iterator, AsciiCounts[Iterator]);
Iterator++;
} while (Iterator <= 255);
/* Print the total length read in */
printf("Total chars read (excluding EOF): %d", --TotalChars);
return 0;
}
Which should achieve the basic goal, however a couple of extension exercises which would likely benefit your understanding of C. First you could try to convert the second do while loop to a for loop, which is more appropriate for the situation but I did not use for simplicity's sake. Second you could add a condition so the output phase skips codes which never occurred. Finally it could be interesting to check which chars are printable and print their value instead of their hex code.
On the second part of the question, the reason those arguments are passed to main even though they are ignored is due to the standard calling convention of c programs under most OSes, they pass the number of command line arguments and values of each command line argument respectively in case the program wishes to check them. However if you really will not use them you can in most compilers just use main() instead however this makes things more difficult later if you choose to add command line options and has no performance benefit.

Resources