Why won't this array get printed? - c

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.

Related

Why are there random characters outputting in my code?

I have been writing a program to input a phrase and turn it into an acronym. For some reason when I output my acronym at the moment it comes out with a bunch of random characters. How do I fix it?
#include <stdio.h>
#include <string.h>
#define MAXLEN 50
int main() {
int num;
printf("Enter number of acronyms to add to the database:");
scanf("%d", &num);
getchar();
char strings[num][MAXLEN];
char acronym[num][MAXLEN];
for(int i = 0; i < num; i++){
printf("Enter the string to convert into an acronym:");
fgets(strings[i],MAXLEN,stdin);
printf("%s\n", strings[i]);
for(int j = 0; j < 11; j++){
if((strings[i][j]) >= 'A' && (strings[i][j]) <= 'Z'){
char buffer[][20] = {strings[i][j]};
strcat(acronym[i], buffer[i]);
}
}
puts(acronym[i]);
}
return 0;
}
I have tried changing the MAXLEN value to see if it was a memory issue or like a buffer overload. I've also just tried changing around how the strings switch and work together but nothing has worked.
char buffer[][20] = {strings[i][j]};
Here you let the compiler count how many elements the array has from the initialization.
It has 1 element, A string with single a single character strings[i][j] and rest of the 20 byte array filled with 0.
strcat(acronym[i], buffer[i]);
Here you access buffer[i], but there is only one string there (as explained above), so this is invalid if i is anything but 0.
I'm not sure what you are trying to do, but this would be valid implementation of what this code tries to do:
// extract single character as a string
char buffer[2] = {strings[i][j], 0}; // only one of 2 and 0 is mandatory
// append it to acronym
strncat(acronym[i], 20, buffer);
Probably lots of other stuff there is wrong, but here is one definite issue and a possible solution.

Create an array of unknown strings - Undefined behaviour

In what way is the following code faulty or undefined behaviour?
I suggested this as a possibility to create an array of strings, if string number and size are unknown beforehand, and after a short discussion, it was suggested that I open a new question.
The following code produced the expected results when I compiled it with gcc, but that can happen in spite of undefined behaviour (it's undefined after all).
So, what is the mistake?
int n, i;
printf("How many strings? ");
scanf("%d", &n);
char *words[n];
for (i = 0; i < n; ++i) {
printf("Input %d. string: ", i + 1);
scanf("%s", &words[i]);
}
for (i = 0; i < n; ++i) {
printf("%s\n", &words[i]);
}
Edit:
I feel stupid now for missing this, I guess getting the correct answer back just made me miss my error. But that others may learn from my mistake:
I guess I got completely wrong what the & operator does. I thought it would give me where words points to, but of course it does the exact opposite. See the answers.
scanf("%s", &words[i]); and printf("%s\n", &words[i]); invokes *undefined behavior because data having wrong type are passed.
In both of scanf() and printf(), %s requires char* pointing at valid buffer but what is passed are char**.
Also don't forget to allocate buffer to store strings before reading.
Try this:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int n, i;
printf("How many strings? ");
scanf("%d", &n);
char *words[n];
for (i = 0; i < n; ++i) {
printf("Input %d. string: ", i + 1);
words[i] = malloc(1024001); /* allocate enough buffer */
if (words[i] == NULL) {
perror("malloc");
return 1;
}
scanf("%1024000s", words[i]); /* limit length to read to avoid buffer overrun */
}
for (i = 0; i < n; ++i) {
printf("%s\n", words[i]);
}
for (i = 0; i < n; ++i) {
free(words[i]); /* clean what is allocated */
}
return 0;
}
char *words[n];
creates an array of uninitialized pointers
scanf("%s", foo);
writes values to the position foo is pointing to
it is not specified where the pointers of words are pointing to so they could point anywhere which could result in a segfault
next words is a char**
words[i] is a char *
&words[i] is a char **
%s expects a char* so it's again undefined behavior what happens
so you first have to initialize your words arrays using for example malloc and then write the values to words[i]
This:
char *word;
is a pointer, Before it is used as a container for say a string, it needs to point to memory sufficient for the string.
for example, this will work
word = malloc(80*sizeof(*word));
if(word)
{//success, continue
Similar to above, this:
char *word[n];
extension is an an array of n pointers. Before any of the pointers can be used as a container for say some strings, each needs to point to its own memory location. Assuming the value n has been scanned in, this will work:
for(int i=0;i<n;i++)
{
word[i] = malloc(80*sizeof(*word[i]));//80 for illustration
if(!word[i])
{//handle error...
Once the memory is allocated, the strings can be populated.
However, to ensure user input does not overflow the buffer defined by each instance of word, use a width specifier in the format string:
Change:
scanf("%s", &words[i]);
To:
scanf("%79s", words[i]);//note & is not needed as the symbol for a char array serves as the address
// ^^ ^

While reading two array in c through scanf, the second one somehow modify the first [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 5 years ago.
Improve this question
I have the following problem reading two strings through scanf: I insert the first string and everything it's OK, but after I insert the second one the first one changes.
#include<stdio.h>
#define N 6
#define K 2
int main(){
char a[N];
char b[K];
int i = 0,j=0;
printf("first word\n\n\n");
scanf("%s", a);
for(i = 0; i <= N; i++){
printf("%c", a[i]);
}
printf("second word \n\n\n");
scanf("%s", b);
for(i = 0; i <= N; i++){
printf("%c", a[i]);
}
}
The first time it prints it correctly. The second time it prints a similar string (maybe the first scanf is still getting the input when I'm inserting the second one)
To begin, you are printing the array a twice; it seems that you mean to print b with the second loop. But there is a problem in your loops. They are going out of array bounds. Since arrays are zero-indexed in C, you need:
for (i = 0; i < N; i++) {}
for a, and:
for (i = 0;i < K; i++) {}
for b.
But even this is not quite right, since the input strings may not entirely fill the arrays. You really need to terminate the loop when the null-terminator is reached, or when the end of the array has been reached:
for (i = 0; a[i] != '\0' && i < N; i++) {}
and:
for (i = 0; b[i] != '\0' && i < K; i++) {}
Of course, it would be simpler to just use puts() to print the strings.
It seems that the inputs (abcabc and abc) were too large for the arrays, causing buffer overflow. This can be avoided by specifying maximum widths when using the %s conversion specifier with scanf().
Here is a modified version of the posted code. I increased the sizes of N and K by one, since it appears that space for null-terminators was not considered in the original code:
#include <stdio.h>
#define N 7
#define K 3
int main(void)
{
char a[N];
char b[K];
int i = 0;
printf("first word\n\n\n");
scanf("%6s", a);
for (i = 0; a[i] != '\0' && i < N; i++) {
printf("%c", a[i]);
}
putchar('\n');
printf("second word \n\n\n");
scanf("%2s", b);
for (i = 0; b[i] != '\0' && i < K; i++) {
printf("%c", b[i]);
}
putchar('\n');
return 0;
}
You are printing a twice, change the second printf("%c", a[i]); to printf("%c", b[i]); .
The problem you are experiencing is because you invoke undefined behavior by failing to insure the strings are nul-terminated and by using incorrect limits regarding b. For instance, you
#define N 6
#define K 2
...
char a[N], b[K];
a can hold a total of 5-chars + the nul-terminator, for a total of 6-chars. b on the other hand, can only hold 1-char + the nul-terminator for a total of 2-chars.
When you then subsequently loop of both a and b with for(i = 0; i <= N; i++), not only have you guaranteed to access an element outside the bounds of the array, e.g. a[6] (valid indexes are 0-5), you have also invoked undefined behavior for any a with less that 6 total characters by attempting to read from an uninitialized value (those uninitialized array elements after the last valid char in word of say, 3-chars) When you invoke Undefined Behavior, the execution of your code is unreliable from that moment forward.
In your case you can eliminate undefined behavior by using field width modifiers to limit the number of characters placed in the arrays by scanf itself, e.g.
if (scanf ("%5s", a) != 1) {
fprintf (stderr, "error: invalid input - a.\n");
return 1;
}
You validate the return of scanf to insure the proper number of conversions have taken place, or you handle the error if they have not.
You prevent reading beyond the bounds of the array by limiting your read and output char loop to only valid characters within the array. You do that by checking the character to be printed is not the nul-terminating character, and when the nul-terminating character is reached, you exit the loop without attempting to print it.
Putting those pieces together, you could do something similar to the following (note j is unused in your code so it is commented out):
#include <stdio.h>
#define N 6
#define K 2
int main (void ) {
char a[N], b[K];
int i = 0/*, j = 0*/;
printf ("enter first word: ");
if (scanf ("%5s", a) != 1) {
fprintf (stderr, "error: invalid input - a.\n");
return 1;
}
for (i = 0; a[i] && i < N; i++)
printf ("%c", a[i]);
putchar ('\n');
printf ("enter second word: ");
if (scanf ("%1s", b) != 1) {
fprintf (stderr, "error: invalid input - b.\n");
return 1;
}
for (i = 0; b[i] && i < N; i++)
printf ("%c", b[i]);
putchar ('\n');
return 0;
}
Example Use/Output
$ ./bin/twowords
enter first word: cats
cats
enter second word: dogs
d
I would strongly caution you to consider reading line-oriented input with a line-oriented input function like fgets. This eliminates many pitfalls for new programmers. The only additional step when using fgets is to recall it reads up-to-and-including the trailing '\n', so you need to trim the '\n' from the string read.
Look things over an let me know if you have further questions.
For the second printf you have to write
printf("%c", b[i]);
As per inputs(abcabc and abc ) you mentioned your are providing to scanf are causing overflow for both the variables a and b,
You should enter string of length 5 for first and 1 for second keeping space for \0 for both the strings
Edit: Also change loop condition from i <= N to i<N or i<sizeof(a).
Please note the loop will print garbage characters past string length if the length of string happens to be less than 5
I see two things that you can do here:
Use another big buffer array that you will load data to, and that copy data to specyfic array. Than you will get max 6 letters of first word in a[], and max 2 letters of second word in b[]. But you will be able to load 2 words.
Scanf specyfic amount of chars like #xing mentiond in comment.
scanf("%6s",word) //general use, not in OP's case
Than when you've got longer word than size that you set up, you will have the rest of input as input in second word.

Why is my program crashing when I debug?

I've started to write a program that reads and stores team info and stores in a structure, reorders and prints results.
First i'm trying to read team names and stores them in a member in a structure, then read team scores and store them in another member.
However, as soon as i debug the file, it crashes. It doesn't even start correctly. I get this error
Unhandled exception at 0xFEFEFEFE in PA2.exe: 0xC0000005 Access
violation executing location 0xFEFEFEFE.
I've backtracked enough to figure out that it is somewhere in the while loop but can't figure out what's wrong with it.
I am using visual studio 2012 and i get no errors when i build it.
#include "stdafx.h"
#include "string.h"
#include <stdio.h>
struct team
{
char name[20];
int no_games;
int points;
int goals_scored;
int goals_let;
};
int main(void)
{
FILE *input2a;
FILE *input2b;
int error1;
int error2;
int i;
char team1_name[20];
char team2_name[20];
int team1_goals;
int team2_goals;
struct team teamlist[20];
error1 = fopen_s(&input2a, "C:\\Users\\New PC\\Desktop\\input2a.dat", "r");
i = 0;
while (i < 20)
{
i ++;
fscanf_s(input2a, "%s", teamlist[i].name);
}
error2 = fopen_s(&input2b, "C:\\Users\\New PC\\Desktop\\input2b.dat", "r");
while (fscanf_s(input2b, "%s %d %s %d", team1_name, &team1_goals, team2_name, &team2_goals) !=EOF)
{
if (team1_goals < 0)
{
printf("Team %s has negative goals - Invalid entry\n", team1_name);
}
else if (team2_goals < 0)
{
printf("Team %s has negative goals - Invalid entry\n", team2_name);
}
else
{
}
}
return 0;
}
From only looking at the while loop: you write to memory out of bounds.
struct team teamlist[20];
And in the while:
i = 0;
while (i < 20)
{
i ++;
fscanf_s(input2a, "%s", teamlist[i].name);
}
So you enter the while when i=19 and increase it to 20 which makes it out of the bounds for the array.
The problem is here (see my comment):
i = 0;
while (i < 20)
{
i ++; // was 19, become 20, but maximal allowed value is 19
fscanf_s(input2a, "%s", teamlist[i].name);
}
The name of this problem is ABW (array bounds write). It means, that your program writes outside array (it happens when i==19, so the condition of the loop i < 20 is satisfied, but right after it you increase it: i++). To fix it you need just to swap two lines of the body of this loop:
{
fscanf_s(input2a, "%s", teamlist[i].name);
i++;
}
And much better and simplier it would be to use for loop here:
for (i = 0; i < 20; i++)
fscanf_s(input2a, "%s", teamlist[i].name);
And the last fix: now there is still possible ABW error. The reason of it is simple: size of teamlist[i].name is 20. So, if input file contains long lines, your program will write outside this array. To fix it you can extend "%s this way (we have here "19" instead of "20" because last character is '\0'):
for (i = 0; i < 20; i++)
fscanf_s(input2a, "%19s", teamlist[i].name);
And one more thing about fscanf_s(): this function shall return the number of successfully matched and assigned input items. So in the second loop it is better to check, that it returns 4.
Update:
If nothing happens, let's open documentation:
Unlike scanf and wscanf, scanf_s and wscanf_s require the buffer size
to be specified for all input parameters of type c, C, s, S, or string
control sets that are enclosed in []. The buffer size in characters is
passed as an additional parameter immediately following the pointer to
the buffer or variable. For example, if you are reading a string, the
buffer size for that string is passed as follows:
char s[10];
scanf_s("%9s", s, _countof(s)); // buffer size is 10, width specification is 9
So in your case in means, that first loop should be corrected this way:
for (i = 0; i < 20; i++)
fscanf_s(input2a, "%19s", teamlist[i].name, _countof(teamlist[i].name));
And you need the same fix for next call of fscanf_s in the second loop, because there are two "%s"s in that call.

Error using 'free' on char array

I'm new to C and trying to write a command line program with it. I'm trying to free a char array right before the program terminates. But I'm getting a "debug assertion failed" run-time error when it reaches the free command. Before it reaches that point, the program is removing characters in that array up until the first whitespace. I'm using the incrementing technique on the array since I read that was a way to remove chars one by one from an array. Here's that piece of code:
char command[140];
char * input = getInput(); //prompt function for user input
//get string up to first whitespace to separate the command and its parameters
for (i = 0; i < strlen(input); i++)
{
if (input[i] == ' ' || input[i] == '\0')
break;
command[i] = input[i];
}
for (j = 0; j <= i; j++) //removes command and space and leaves parameters
input++;
command[i] = '\0'; //null terminate char array
numParams = getNumParams(input);
free(input); //should've added this line earlier to avoid confusion.
My getInput() function does this:
char * getInput()
{
int n, size = 260;
char * input = (char*)malloc(size);
if (!input) //make sure memory allocation worked
return NULL;
do
{
printf("cmd> "); //prompt
fgets(input, 256, stdin); //get user input/commands
n = strlen(input);
} while (n <= 1);
if (input[n - 1] == '\n') //remove new line from input array
input[n - 1] = '\0';
return input;
}
So after the rest of the program ends I want to be able to free the memory that was allocated in the getInput() function. I'm thinking the way I have the input returning to a char pointer is messing that up. But I'm not sure how to fix it. Any help is appreciated.
You haven't posted the line that calls free. I am assuming that you are calling:
free(input);
I can see why that would be a problem.
You are changing the value of input in the lines:
for (j = 0; j <= i; j++)
input++;
When you call free, the value of the pointer must be what was returned by malloc, calloc, or realloc. If you use any other pointer value, the program is subject to undefined behavior.
Make sure that you keep the value that was returned, so you can call free using it.
char* input = getInput();
char* saved_ptr = input;
// ...
// Change input
// ...
// Deallocate memory using the original pointer
free(saved_ptr);
The problem is most likely these two lines:
for (j = 0; j <= i; j++) //removes command and space and leaves parameters
input++;
Here you modify the pointer, making you loose the original pointer that you should pass to free. You need to save the original pointer in a temporary variable, and pass that to free.
You get an error because you are modifying the input pointer here:
for (j = 0; j <= i; j++) //removes command and space and leaves parameters
input++;
After this operation, input no longer points to the start of memory, allocated by malloc. Thus giving you the error. Instead, copy input to another pointer variable.
Also, consider doing allocation outside of getInput() since it is considered a good practice to allocate and free the memory in the same function, if possible.

Resources