Why can't I list strings stored in arrays? - c

I started learning C recently. I'm having some difficulty with strings, especially in the matter of storing list of names, phrases, words and displaying them later. Here's my code:
#include <stdio.h>
int main()
{
char names[3][10];
printf("Type 3 names: \n");
for (int i = 0; i<3; i++)
{
scanf("%10s", names);
}
printf("\n\nName list:\n\n");
for (int j = 0; j<3; j++)
{
for (int k = 0; k<10; k++)
{
printf("%s", names[k][j]);
}
}
return 0;
}
My intention is to store full names and with spaces and display them listed later.
When I run the code, the program does not ask for 3 names and does not display correctly the ones that have been typed.
Any tips on how I can fix it?

Please turn up the warning level of your compiler. It should have warned you about at least two things:
(20): warning C4477: 'printf' : format string '%s' requires an argument of type 'char *', but variadic argument 1 has type 'int'
(20): warning C4313: 'printf': '%s' in format string conflicts with argument 1 of type 'int'
In your first for-loop you do count to 3 but you miss specifying that you want to read from stdin to names[i]. Change
scanf("%10s", names);
to
scanf("%10s", names[i]);
In your second loop the nested for-loop is not neccessary since printf() will take care of printing each char in names[j] until it encounters a '\0' which terminates the string. So change
for (int j = 0; j<3; j++)
{
for (int k = 0; k<10; k++)
{
printf("%s", names[k][j]); // doesn't match. names[i][j] is a char *)
}
}
*) which propagates to an int due to parameter passing to a function with a variable length parameter list while the format string "%s" causes printf() to expect a pointer to char.
to
for (int j = 0; j < 3; j++)
{
printf("%s\n", names[j]);
}
Please also mind that since you want to read names up to 10 characters in length your array needs to be
char names[3][11]; // not [3][10]
to accomodate for the terminating '\0' character.

Related

Why won't this array get printed?

I'm trying to write a program to take 10 words as input from the user, then store it an array, and then print out the length of each word.
Here's my code:
#include <stdio.h>
#include <string.h>
char *words[10];
char length[10];
int i, j;
int main()
{
printf("Input ten words: \n");
for(i = 0; i < 10; i++)
{
printf("Enter element %d \n", i + 1);
scanf("%s", &words[i]);
}
for(i = 0; i < 10; i++)
printf("%c", words[i]);
for(i = j = 0; j < 10; j++)
{
length[j] = strlen(words[i]);
i++;
}
for(j = 0; j < 10; j++)
printf("%c", length[j]);
return 0;
}
It should be noted that I have no idea why the array "words" is defined as a pointer, I only do it because if I don't I get some warning about making a pointer from integer without a cast.
When I run the program what happens is, I get prompted to input the 10 elements, that much works, but then when it's supposed to print the "words" array, the program just crashes.
Also the reason I coded it like this is because later on I also need to print the longest and shortest word - so I figured it would help if I had the lengths of all the strings in their own array.
Does anyone know what's wrong here?
Thanks
With the line char *words[10], you are declaring an array of 10 pointers. However, these pointers are uninitialized, which means they are wild pointers. Dereferencing a wild pointer causes undefined behavior (i.e. the program may crash). If you want to use these pointers in a meaningful way, you must make each pointer point to a valid memory location, for example to an address returned by the function malloc or to the address of a char array.
However, probably the easiest solution to your problem is to not use pointers at all, but to instead declare a two-dimensional char array, like this:
char words[10][100];
That way, you are allocating space for 10 words of up to 100 characters each (including the null terminating character).
Beware that a buffer overflow will occur if the user enters a word longer than 99 (1 byte is required for the terminating null character). Therefore, the scanf line should be changed to the following:
scanf("%99s", words[i]);
That way, scanf will never attempt to write more than 100 bytes (including the terminating null character).
I have also removed the & in the scanf line above, because the & is not necessary, since words[i] will automatically decay to &words[i][0].
Also, as a general rule, you should verify that the return value of scanf is 1 before attempting to use the value that scanf wrote. For example, if the user triggers end of file on the input stream (for example by pressing CTRL-D on Linux or CTRL-Z on Windows), then scanf will return -1 without writing anything into words[i]. In that case, by subsequently reading from words[i], your program will cause undefined behavior.
Additionally, the line
printf("%c", words[i]);
must be changed to:
printf("%s", words[i]);
The loop
for(i = j = 0; j < 10; j++)
{
length[j] = strlen(words[i]);
i++;
}
can be simplified to:
for(i = 0; i < 10; i++)
{
length[i] = strlen(words[i]);
}
The line
printf("%c", length[j]);
should probably be changed to
printf("%hhu", length[j]);
because length[j] does not represent the ASCII code of a character, but just a number.

Passing an array of characters as function arguments

I am trying to pass a string as an argument to a function and it throws a Segmentation fault(Core Dumped) error. Could you please let me know what mistake I am making here? Here is the code:
replaceChars(char str[], char sChar[], char rChar)
{
int i,j;
printf("rChar is %c", rChar);
printf("sChar is %s", sChar);
for(i = 0; i <= strlen(str); i++)
{
for(j = 0; j <= strlen(sChar); j++)
{
if(str[i] == sChar[j])
{
str[i] = rChar;
//printf("The New String is %c", str[i]);
}
}
}
printf("The New String is %s", str);
}
void main()
{
char myString[36], schar[36], rchar;
printf("Please enter a string:");
scanf("%[^\n]s", &myString);
printf("Which characters to replace?");
scanf(" %[^\n]c", &schar);
printf("With which character?");
scanf(" %[^\n]c", &rchar);
replaceChars(myString, schar, rchar);
}
Two issues here.
First, when you loop through str and sChar:
I am trying to pass a string as an argument to a function and it throws a Segmentation fault(Core Dumped) error. Could you please let me know what mistake I am making here? Here is the code:
for(i = 0; i <= strlen(str); i++)
{
for(j = 0; j <= strlen(sChar); j++)
{
You use <= as your exit condition. Array indexes start from 0, so valid indexes are from 0 to length-1. You're going from 0 to length, so you're stepping of the end of the array. Reading past the end of an array invokes undefined behavior.
Change the conditions to use <:
for(i = 0; i < strlen(str); i++)
{
for(j = 0; j < strlen(sChar); j++)
{
The second problem is in how you're reading the values:
scanf("%[^\n]s", &myString);
...
scanf(" %[^\n]c", &schar);
...
scanf(" %[^\n]c", &rchar);
The %[] format specifier doesn't require any characters after it, and it requires a char * as a parameter which points to the first element of an array of char. In the first two cases, you're passing the address of an array instead of the array itself (which decays to a pointer) and you have an extra character after the %[] format that isn't needed. In the third case you pass a pointer to a single char when a pointer to multiple characters is expected by the format. Because you want to read a single char, you want to use the %c format specifier instead.
scanf("%35[^\n]", myString);
...
scanf(" %35[^\n]", schar);
...
scanf(" %c", &rchar);
Note also that the first two have a field width that limits the number of characters that are read so that you don't overrun the arrays.
Could you please let me know what mistake I am making here?
In addition to #dbush good answer, OP's code is unnecessarily inefficient.
Using the corrected code below, and assume the initial length of the str, sChar are S,C respectively.
for(i = 0; i < strlen(str); i++) {
for(j = 0; j < strlen(sChar); j++) {
if(str[i] == sChar[j]) {
str[i] = rChar;
}
}
}
The for(i = 0; i < strlen(str); i++) { and with the later str[i] = rChar; obliges the code to find the length of str up to S times and each strlen(str) requires O(S) operations.
If S was a non-trivial value, say 1000, this 1000*1000 could readily affect overall performance. A simply solution is to calculate the length once or look for the null character instead.
// for(i = 0; i < strlen(str); i++) {
S = strlen(str);
for(i = 0; i < S; i++) {
// or
for(i = 0; str[i]; i++) {
The same thing happens with the inner loop too. Yet a smart compiler can see that sChar does not change and may take advantage of understanding strlen() has no side effects that would cause for a different result. With such an optimization strlen(sChar) may be truly called once, even if strlen(sChar) in inside the higher for (i...) loop.
Still it is easy and idiomatic to just test for the null character.
// for(j = 0; j < strlen(sChar); j++)
// better as
for(j = 0; sChar[j]; j++)
Yet why does this not apply to the for(i = 0; i < strlen(str); i++) loop?
Within that loop, code can modify str[] and so the compiler cannot make the optimization as with for(j = 0; sChar[j]; j++).
This also begs the question, what should code do if the replacement character rChar is the null character?
As I see it, code could either continue, replacing with a '\0 multiple times or simple return after this first.
str[i] = rChar;
if (rChar == '\0') return; // Possible way to handle \0

warning: format '%s' expects argument of type 'char *', but argument 2 has type 'char'

First of all, this code(PenaltyShootout.c) is used to count the number of 1's in a given string which are preceded by 2.
"0" - No goal,
"1" - Goal,
"2" - Foul.
Problem: PenatltyShootout.exe stopped working.
#include <stdio.h>
#include <string.h>
int main()
{
int T,i;
char str[100][500];
int n=0;
No. of test cases are the no. of different strings to input to check the working of code.
do
{
printf("Enter the number of Test cases(must be between 1 and 100):\n");
scanf("%d",&T);
}while(T>100);
I tried replacing str[i][500] with (char *) str[i][500] and the warning vanished, yet PenaltyShootout.exe stopped working.
for(i=0; i<T; i++)
{
printf("Enter the test case %d\n",i);
scanf("%s",str[i][500]);
}
for(i=0; i<T; i++)
{
for(int j=0; j<strlen(str[i])-1; j++)
{
if((str[i][j]=='2')&&(str[i][j+1]=='1')==1)
{
n++;
}
}
This should print the number of goals made after making a foul.
printf("%d\n",n);
}
return 0;
}
Your call to scanf("%s", str[i][500]); is reading a string ("%s") into a character (str[i][500]).
If you are trying to read a single letter from the prompt, you need to switch it up like this:
scanf("%c", &str[i][500]);
That "%c" lets scanf() know you want a single letter, and that & tells it to use the address of a character in memory (str[i][500], the 501th position in str[i] (when you only have 500 allocated)) for where to put it.
If you are trying to read a string (i.e. a word or sentence) you need to switch it up more like this:
scanf("%s", str[i]);
Here, you are now putting the scanned string into the ith string buffer in str (which you have already allocated 500 chars for).

C: Format %s expects argument of type char* in funny strings program

I am making a program to check for funny strings. To understand the exercise read this.
My code is here:
#define MAX_STR_LENGTH 10
char* reverse(char *str) {
char *reversedStr = malloc(strlen(str));
for (int i = 0; i < MAX_STR_LENGTH; i++) {
for (int j = MAX_STR_LENGTH - 1; j > 0; j--) {
reversedStr[i] = str[j];
}
}
return reversedStr;
}
int isFunny(char *str, char *reversedStr) {
for (int i = 1; i < MAX_STR_LENGTH; i++) {
if (str[i] - str[i - 1] != reversedStr[i] - reversedStr[i - 1]) {
return 0;
}
}
return 1;
}
int main() {
/* Enter your code here. Read input from STDIN. Print output to STDOUT */
int numberOfStrings;
scanf("%i", &numberOfStrings);
char **strings;
for (int i = 0; i < numberOfStrings; i++) {
scanf("%s", &strings[i]);
}
char **reversedStrings;
for (int i = 0; i < numberOfStrings; i++) {
reversedStrings[i] = reverse(strings[i]);
}
for (int i = 0; i < numberOfStrings; i++) {
if (isFunny(strings[i], reversedStrings[i])) {
printf("Funny\n");
}
printf("Not funny\n");
}
return 0;
}
The error I am getting is the following:
solution.c: In function 'main':
solution.c:35:9: warning: format '%s' expects argument of type 'char *', but argument 2 has type 'char **' [-Wformat=]
scanf("%s", &strings[i]);
I don't understand why though.
My aim was to make an array of strings, called strings, and store there all the strings that I read. Why is strings[i] a char** ?
I would appreciate any help or tips.
Thanks!
Apparently you have a char * and you are passing it's address, which is wrong, scanf() wants a char pointer for each "%s" specifier, and the fix for your code is to use
char string[10];
scanf("%s", string);
the array automatically becomes a char pointer when passed to scanf() like above, but that's not enough.
Your array of char now as I suggest it is of fixed size, and even if it wasn't, using scanf() like that is dangerous, suppose that each array in the array of char arrays has 10 elements, then each string you want to read must have only 9 characters, you can instruct scanf() to stop reading when it already read 9 characters like this
scanf("%9s", strings[i]);
If you don't do this, then reading extra characters will be possible, but illegal, causing what's called undefined behavior.
If you want an array of strings, say of 5 strings with 9 characters each, then you can try
char strings[5][10];
int i;
for (i = 0 ; i < 5 ; ++i)
scanf("%9s", strings[i]);
Note: You need the & address of operator for example, when you pass an int value, because scanf() modifes the data pointed to by the passed pointer, so you need to make a pointer to the int variable where you want to scan the value, for that you use the & address of operator, since you pass a pointer containing the address of the variable.
Suggestion: Always check the return value of malloc(), it returns NULL on failure, and dereferencing a NULL poitner, is undefined behavior, you must be careful not to cause undefined behavior because it's too hard to debug.

automatic newline printed in C

Here's my code:
void fun1(char data[2][10]);//function prototype
int i, j; char data[2][11];//variables
for (i = 0; i < 2; i++)//populating the 2D array of chars
{
for (j = 0; j < 11; j++)
{
scanf("%c", &data[i][j]);
}
}
fun1(data);
void fun1(char data[2][10])//function to print the array out
{
int i, j, sum;
printf("\n");
for (i = 0; i < 2; i++)
{
for (j = 0; j < 11; j++)
{
printf("%c", data[i][j]);
}
}
}
This is my inputs and outputs:
(inputs)
aaabbbccce
aaabbbccce
(outputs)
aaabbbccce
aaabbbccce
My question is why is there a newline in the output when i haven't specified one?
By the way, is it ok if my function parameters dont match the size of my array? Like my array is char data[2][11] and the parameter i passed in is char data[2][10].
Change all those '11' to '10'
You declareed fun1() as void fun1(char data[][10]), but gave it an argument of type char [][11].
Change scanf("%c", ...) to scanf(" %c", ...)
The space before % will ignore the blank characters, such as newline, in your input.
Your input
aaabbbccce(enter)
aaabbbccce(enter)
includes 22 characters, not 21 ones. The (enter) after the first 'e' should be ignored.
If you use scanf("%c", ...) to read the input, you should give an input like
aaabbbccceaaabbbccce(enter)
to your program.
You should correct the loop limits from 11 to 10.
You should do it in both the functions. But doing it in fun1() should suffice.
I don't think it's ok if your function parameters don't match the array size, at least you wouldn't get what you want.
As we know, when you use array as a parameter, in fact calling function passes its array's first address(aka the variable name of array) to the called function, and called function receives the first address as its parameter's address, so both the parameters share the same memory.
C allows this, but you might see the warning messages.

Resources