C language printing strings from array in a loop - c

I am making a console application in C using visualstudio 2015 so that a user can enter the amount of sweets they wish to make and the name of the sweet however there is a problem, the problem is that when the program tries to read a string from the array the program crashes and doesnt print out anything, however if I change it to print a single character using %c it will print out the first character of the string for example if I enter 2 sweets and the strings 'Jawbreaker' and 'Lollipop' It will crash if I use %s for the string however if I use %c for a character it will do its job and print 'J' and 'L' respectively on different lines, Any ideas how I could get this working with the %s specifier for the strings?
The code is below:
#include <stdio.h>
/*Declares the variable needed*/
int sweet_number;
char sweet_name[999];
int main(void) {
/*Prompts the user to enter the number of sweets and saves it to sweet_number*/
printf("Please enter the number of sweets:\n");
scanf("%d", &sweet_number);
/*for loop to enter the name of the sweet into the array*/
for (int i = 0; sweet_number > i; i++) {
printf("What is the name of the sweet?\n");
scanf("%s", &sweet_name[i]);
}
/*Prints array to screen*/
for (int j = 0; sweet_number > j; j++){ /* <- This is where code fails to run*/
printf("%s\n", sweet_name[j]);
}
return 0;
}

You have to use an 2-dimensional array. sweet_name is an array(1-D), each index can store at most one character not a string. Change the following line
char sweet_name[999];
to
char sweet_name[999][100];

OK, I would advice you doing something more efficient and that is to use a double pointer. By doing that, you can solve some problems that the 2D array version has.
The first problem is, what do you do if the user wants to insert more than 999 sweets. Your array can't hold them.
Second, what do you do if the user enters a name that is bigger than 100 characterrs. Again, your 2D array can't hold it. And also, although there is the possibility for the user to enter a name bigger than 100 characters, most users will enter much less than this and now for every string, you have allocated 100 positions when you probably only need about 50. So, let's deal with these problems.
I would probably do something like this:
#include <stdio.h>
#include <string.h> // for strcpy(), strlen()
#include <stdlib.h> // for malloc()
int main(void) {
char **sweet_names; // make a double pointer(or you might see that as array of pointers
char reader[300]; // this variable will help us read every name into the sweet_names
int sweet_number;
int i, j;
// Your code here to get the number of sweet_names
/*Prompts the user to enter the number of sweets and saves it to sweet_number*/
printf("Please enter the number of sweets:\n");
scanf("%d", &sweet_number);
// Now that you know the sweet_number, allocate as much memory as you need.
// And that can be more than 999 sweet names
sweet_names = (char **) malloc(sweet_number * sizeof(char *));
// i.e. make a character pointer to sweet_number character pointers.
// Again, some of your code here
for (i = 0; sweet_number > i; i++) {
printf("What is the name of the sweet?\n");
scanf("%s", reader); // read into the reader
sweet_names[i] = (char *) malloc(strlen(reader) + 1); // allocate as much memory as you need for the current string, the one just read into reader
strcpy(sweet_names[i], reader); // copy contents of reader to sweet_names[i]
}
// Again, your code to print the names
for (j = 0; sweet_number > j; j++){
printf("%s\n", sweet_names[j]);
free(sweet_names[j]); // free every string you allocated, it is good practice
}
// Finally, free the sweet_names pointers. Generally, when you allocate
// dynamically, which is what we do with malloc(), it is a good practice
// to free what you allocate becuase otherwise stays in memory and then
// memory leaks are created. There is a lot to say about C and memory
// but anyway, remember to free
free(sweet_names);
return 0;
}
Finally, now the program again has the limitation to read only names up to 300 characters because of reader, but this is something that you can also deal with, and this is to allocate a crazy amount of memory for reader, like 1000000
characters and then free it.

Related

What is the point of assigning the size of a string?

For an instance if I store ABCDE from scanf function, the later printf function gives me ABCDE as output. So what is the point of assigning the size of the string(Here 4).
#include <stdio.h>
int main() {
int c[4];
printf("Enter your name:");
scanf("%s",c);
printf("Your Name is:%s",c);
return 0;
}
I'll start with, don't use int array to store strings!
int c[4] allocates an array of 4 integers. An int is typically 4 bytes, so usually this would be 16 bytes (but might be 8 or 32 or something else on some platforms).
Then, you use this allocation first to read characters with scanf. If you enter ABCDE, it uses up 6 characters (there is an extra 0 byte at the end of the string marking the end, which needs space too), which happens to fit into the memory reserved for array of 4 integers. Now you could be really unlucky and have a platform where int has a so called "trap representation", which would cause your program to crash. But, if you are not writing the code for some very exotic device, there won't be. Now it just so happens, that this code is going to work, for the same reason memcpy is going to work: char type is special in C, and allows copying bytes to and from different types.
Same special treatment happens, when you print the int[4] array with printf using %s format. It works, because char is special.
This also demonstrates how very unsafe scanf and printf are. They happily accept c you give them, and assume it is a char array with valid size and data.
But, don't do this. If you want to store a string, use char array. Correct code for this would be:
#include <stdio.h>
int main() {
char c[16]; // fits 15 characters plus terminating 0
printf("Enter your name:");
int items = scanf("%15s",c); // note: added maximum characters
// scanf returns number of items read successfully, *always* check that!
if (items != 1) {
return 1; // exit with error, maybe add printing error message
}
printf("Your Name is: %s\n",c); // note added newline, just as an example
return 0;
}
The size of an array must be defined while declaring a C String variable because it is used to calculate how many characters are going to be stored inside the string variable and thus how much memory will be reserved for your string. If you exceed that amount the result is undefined behavior.
You have used int c , not char c . In C, a char is only 1 byte long, while a int is 4 bytes. That's why you didn't face any issues.
(Simplifying a fair amount)
When you initialize that array of length 4, C goes and finds a free spot in memory that has enough consecutive space to store 4 integers. But if you try to set c[4] to something, C will write that thing in the memory just after your array. Who knows what’s there? That might not be free, so you might be overwriting something important (generally bad). Also, if you do some stuff, and then come back, something else might’ve used that memory slot (properly) and overwritten your data, replacing it with bizarre, unrelated, and useless (to you) data.
In C language the last of the string is '\0'.
If you print with the below function, you can see the last character of the string.
scanf("%s", c); add the last character, '\0'.
So, if you use another function, getc, getch .., you should consider adding the laster character by yourself.
#include<stdio.h>
#include<string.h>
int main(){
char c[4+1]; // You should add +1 for the '\0' character.
char *p;
int len;
printf("Enter your name:");
scanf("%s", c);
len = strlen(c);
printf("Your Name is:%s (%d)\n", c, len);
p = c;
do {
printf("%x\n", *(p++));
} while((len--)+1);
return 0;
}
Enter your name:1234
Your Name is:1234 (4)
31
32
33
34
0 --> last character added by scanf("%s);
ffffffae --> garbage

Is it possible to use a strcpy inside a scanf or a sscanf? (in C language)

I read somewhere that when we use structs we can't just write something like «example1.name = "Jim";», instead of it we should write «strcpy(example1.name, "Jim");»
The thing is that I need to use a struct and I need to scanf (and right after that sscanf) some information that corresponds to a string and I don't know how I should do it.
Could somebody help me, please?
Edit:
My code isn't complete and I know it's wrong, but I'll post it here so that you know what I am talking about:
int main(){
struct Cards{
int value;
char type[4];
};
for(i=1, 0 < i && i < 11, i++){
struct Cards cardi;
}
scanf("%d %s", &cardi.value, cardi.type);
/*at this point I just know it's wrong but I am really bugged.
I thought about something like «scanf("%d %s", &cardi.value, strcpy(cardi.type, "%s"));»
but I just know it's very wrong */
return 0;
}
This isn't true only about structs, but for all strings. You can use = for strings, only when you initialize them. You can scanf a string and place it in a string. Example:
scanf("%s", my_struct.str);
If you already have a string and you want to pass it in a struct, or in an other string variable you then need strcpy:
char str1[] = "abc", str2[4];
strcpy(str2, str1);
or
strcpy(my_struct.str, str1);
Edit:
for(i=1, 0 < i && i < 11, i++) {
struct Cards cardi;
}
In your code cardi is not card0, card1 etc, it is a struct Cards variable with the name cardi.
If you want to store 10 cards, you sould make an array of struct Cards with capacity of 10 like:
struct Cards array[10];
for (i = 0; i < 10; i++) {
scanf("%d %s", &array[i].value, array[i].type);
}
Anyway i suggest that you focus on learning the basics on arrays, strings and pointers before you use structs.
Edit 2: You don't want to define structs inside your main, because in that way, if you write a function it will not "see" your struct. Structs usually are written in the top of the code.
Your use of scanf() is correct. However scanning strings using %s is dangerous and discouraged. This is because the type member of your structure has space for only 4 characters, including the terminating '\0' (NUL) character. Entering a string longer than 3 characters will result in the extra characters being written into an unknown area of memory likely corrupting other variables and leading to incorrect program execution or a program crash. You can correct this by adding a string length limit, simply replace %s with %3s, where 3 is the maximum numbers of characters that will be accepted (scanf will automatically add a '\0' (NUL) character following the last scanned character).
Below are some additional comments:
If you want to declare an array for 10 Cards, you could do it this way without any loops:
struct Cards cardi[10];
To scan values into the first card (C arrays are 0-based):
// this will scan into the first card; type field is restricted to at most 3 characters
scanf("%d %3s", &cardi[0].value, cardi[0].type);
At the top of the file you'll want to add:
#include <stdio.h>
This header file provides a prototype (declaration) for the scanf function (among many others).

Why can't i declare a more than three digits array of array of char in C?

I am writing a program that takes an integer and then makes array of arrays of char and finds the number of every occurrence of every char in all lines. This two dimensional array has the size of "lineNumber". The code is shown below.
The problem is when i get an input more than 3 digits, it stops working and exits. I really found that the problem is with declaring the array of array of chars. Can you tell me how to overcome this problem? For example i want to take an input of 1000 line?
The problem is not with the scanf function, i know that. Can you fix my code?
printf("Number of lines: ");
int lineNumber;
int n = scanf("%d", &lineNumber);
if (n == 0) {
puts("Use integers.");
return n;
}
char lines[lineNumber][1024]; /* It can't declare more than 3 digit integer */
int i = 0;
for (;i < lineNumber; i++) {
printf("%d: ", i+1);
fgets(lines[i], 1024, stdin);
lines[i][strlen(lines[i])-1] = '\0';
}
/* count the number of occurrence of every char in all lines */
If lineNumber is for example 9000:
char lineptr[lineNumber][1024];
then lineptr uses about 9000*1024 = 9MB of stack space. Depending on your os and system configuration, this might be too much crashing your program. Stack space is usually limited.
If you need a big amount of space, better allocate the memory with malloc().

Deciding how much memory to dynamically allocate based on user input

I need to write a program that does the following:
Prompt the user and ask them how many words they wish to enter
Allocate dynamic memory using malloc() to store each individual word
Dynamically allocate another array to store pointers to each of these individual word strings, fill it with the pointers
Dynamically allocate an additional array for temporary storage of an incoming word
Prompt the user to enter a string with the same number of words they previously entered.
Read the users' input into the temporary array one word at a time, once each word has been read, transfer it into one of the dynamically allocated arrays.
After all of this I should be able to print each word individually.
A sample run could look like this:
How many words do you wish to enter? 5
Enter 5 words now:
I enjoyed doing this exercise
Here are your words:
I
enjoyed
doing
this
exercise
When reading the string, the program should read the word into a temporary array of char, use malloc() to allocate enough storage to hold the word, and store the address in the array of char pointers.How to handle this step?
Here is my question: How can I size my temporary array to be large enough to hold any arbitrary word the user may enter, and then how do I transfer it to the storage array?
#include <stdio.h>
#include <stdlib.h>
enum { MAX_WORD_SIZE = sizeof("Supercalifragilisticexpialidocious") };
void resign(char**,int);
int main()
{
char **p;
int n,i;
printf("How many words do you wish to enter?");
scanf("%d",&n);
p=calloc(n, sizeof(char*));
puts("Here are your words:");
resign(p,n);
for (i=0; i<n; i++) {
puts(p[i]);
}
}
void resign(char**p,int n)
{
int i=0,j=0;
char c;
char * temp_word = NULL;
getchar();
temp_word = malloc(MAX_WORD_SIZE);
while ((c=getchar())!='\n') {
if (c!=' ') temp_word[i++]=c;
else {temp_word[i]='\0';
p[j]=temp_word;
temp_word = malloc(MAX_WORD_SIZE);
i=0;j++;}
}
temp_word[i]='\0';
p[j]=temp_word;
free(temp_word);
}
Here is a description of malloc().
It takes a parameter size, in bytes.
So if the user entered 5 words, then you need to first allocate an array big enough to store 5 pointers.
Eg.
char ** words = NULL;
words = malloc(sizeof(char *) * <NUMBER OF CHARACTERS THE USER ENTERED>);
If we assume ASCII is being used and a character is a char, then each letter in each of the words is a byte. We also need to account for any spaces, line feeds, perhaps a carriage return, and a trailing null.
So how many letters are in a word? IDK, that's up to you. But if we assume that "Supercalifragilisticexpialidocious" from Mary Poppins in the longest word we will encounter, then we need to allocate at least 34 characters, plus an extra for a trailing null terminator. So that leaves us with up to 35 bytes per word.
This will work:
enum { MAX_WORD_SIZE = sizeof("Supercalifragilisticexpialidocious") };
This will also take into account the trailing \0 - MAX_WORD_SIZE will be 35.
char * temp_word = NULL;
temp_word = malloc(MAX_WORD_SIZE);
To create all of your other word arrays you'd need to do something similar in a loop:
for(int i = 0; i< <NUMBER OF WORDS THE USER ENTERED>; i++)
{
words[i] = malloc(MAX_WORD_SIZE);
}
To convert the number of words entered by the user into an integer you should use atoi()
After this you could use getchar() to pull the string from stdin one character at a time and manually place them into temporary you allocated, stopping when you get to a ' ' space.
To copy the temporary array into one of your word arrays you can use strcpy(), just ensure your temporary array always has a trailig \0 after the word.
Don't forget to free() that pointer when you're done.
I am assuming you are doing this for some sort of a homework assignment on dynamic memory and that is why your application is defined the way it is. But if you aren't you should consider just reading the input into one buffer first using fgets() and using strtok() to split the string after its been read. That approach will take more memory but it would be cleaner.
Another thing you should consider doing is using calloc() instead of malloc() to do your allocation, that way you can ensure that all of your arrays are initialized with 0's - it could save you from some confusion later on if there is garbage data already in those arrays.
Yet another thing to think about: The temporary array in this example can be allocated automatically or statically using temp_word[MAX_WORD_SIZE]; since I used an enum to store MAX_WORD_SIZE as a constant. There is no direct need to use malloc for this.

How to check each character in a dynamically allocated string array, in C?

So what I am trying to ultimately do is search an array for a name, and if the name is found return that name. Well, to do that I need to check for each character in every row and column for a match. And before I could do that I need to know exactly how to go about doing that, so I am trying to figure out how to get the dynamic array to print out the first character, then second and so on in order to compare it with the name being searched. But I am having trouble doing this. So my question is how would I go about checking each character in such an array? I've let out most parts of the code but I think I included the main parts that I am troubled in. Thanks for the help in advance.
I'm a beginner in C, so sorry if I did anything gravely wrong, thanks!
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define STRINGSIZE 20
int main(){
char **firstNames, **lastNames;
int classSize,i;
char sample[21] = "Slack";
printf("Please indicate number of records you want to enter (min 5, max 15):\n");
scanf("%d", &classSize);
firstNames=malloc(classSize*sizeof(char*));
for (i=0; i<classSize; i++) {
firstNames[i]=malloc(STRINGSIZE*sizeof(char));
}
printf("Please input records of students (enter a new line after each record), with following format: first name");
*firstNames="Slack";
printf("\n\n");
printf("%c", *(sample)); //Will print out S
printf("%c", **firstNames); //Will print out S
printf("%c", *(sample+1)); //Will print out l
printf("%c", **(firstNames+1)); //Will give error
printf("%c", **(firstNames)+1); //Will print T (Next ascii char after 'S'
printf("%c", **((firstNames)+1)); //Will give error
}
A C string is an array of characters. Even if dynamically allocated, you can treat it as such, so:
sample[0]; // S
sample[1]; // l
sample[2]; // a
// etc
You are storing multiple pointers to C strings in firstNames. You access it as an array:
firstNames[0]; // first name
firstNames[1]; // second name
firstNames[2]; // third name
// etc.
Now you just combine these, as firstName[0] is just a C string, just like sample:
firstName[0][0]; // first letter in first name
firstName[0][1]; // second letter in first name
firstName[1][0]; // first letter in second na,e
// etc.
You have an array of pointers to char firstNames the size of classSize. Every pointer in this array points to valid memory you allocated with malloc.
The error you make is assigning a string literal to the first pointer of the array firstNames, overwriting the pointer with the address of the string literal. This will lose the memory you allocated and also the string literal cannot be modified, which you do later causing the program to crash.
This line will copy a string "Slack" to the memory the first pointer in the array points to:
strcpy( firstNames[0] , "Slack" ) ; //make sure you have enough space
Note that firstNames[0] equals to *firstNames.
i used in the for loop is not defined anywhere.

Resources