For Loop Not Terminating with Null Terminator - c

I am working on a machine problem and was tasked to input 'n' arrays that I will then have to “merge sort”.
However, when I execute and input the words, it won't stop at the 'nth' word and will ask me to input more characters even when I made use of a null terminator.
Any help would be much appreciated.
#include <stdio.h>
#include <string.h>
#include "mp1_lib.h"
int main()
{
int n;
printf("\n");
printf("Input n: ");
scanf("%d", &n);
n += 1;
char words[n][16];
initialize(n, words);
get_words(n, words);
print_words(n, words);
printf("\n");
}
void initialize(int n, char words[][16])
{
for (int x=0; x < n; x++)
{
for(int y=0; y < 16; y++)
{
words[x][y] = ' ';
}
}
}
void get_words(int n, char words[][16])
{
char c;
char check = '0';
for(int x = 0; x < n; x++)
{
int y = 0;
while (check != '\0' && y < 16)
{
c = getchar();
words[x][y] = c;
check = c;
y++;
}
}
}
void print_words(int n, char words[][16])
{
for(int x=0; x < n; x++)
{
for(int y=0; y < 16; y++)
{
putchar(words[x][y]);
}
}
}

Since typing a null character can be tricky for the end user, I suggest you change your line to check for other character like an escape character or ESC key which value is 27 and it is easier to type
while (check != 27 && y < 16)

You cannot enter a '\0'-character, which is the same as value 0 or 0x0, through the keyboard. Hence, your loop will not terminate this way.
Usually, when getting input through the keyboard, you will terminate a single string by pressing "enter", represented by the new line character '\n' then.
You could further enhance your program to stop scanning words once an "empty" word is entered, i.e. the length of the word is 0.
See the following program, which makes use of fgets for reading in a string until the next new line character + a common code to remove the new line character itself then:
void get_words(int n, char words[][16])
{
for(int x = 0; x < n; x++)
{
if (fgets(words[x],16,stdin)){
words[x][strcspn(words[x],"\n")] = '\0'; // remove new line (if any)
}
else{
words[x][0] = '\0'; // othwise, set it to an empty string
break;
}
if (words[x][0] == '\0') // empty string entered (or end-of-file reached)
break;
}
}
void print_words(int n, char words[][16])
{
for(int x=0; x < n && words[x][0] != '\0'; x++) {
printf("%s\n",words[x]);
}
}
int main()
{
int n;
printf("\n");
printf("Input n: ");
scanf("%d\n", &n);
n += 1;
char words[n][16];
get_words(n, words);
print_words(n, words);
printf("\n");
}
Note further that your initialize-function does not terminate the strings; This will lead to undefined behaviour once you access the strings then using, for example, with printf.
Suggestion:
void initialize(int n, char words[][16])
{
for (int x=0; x < n; x++)
{
for(int y=0; y < 16; y++)
{
words[x][y] = ' ';
}
words[x][16-1] = '\0';
}
}

Related

printing * corresponding to the number of iteration

So in C I'm supposed to let the user input an integer n from the interval [5, 25]. And then, for every number from 1 to n, in a new line print that many stars so it would look something like this:
*
**
***
I tried doing it like this, but it's not working. What am I doing wrong here?
#include <stdio.h>
int main(void)
{
int n, i;
char star = '*';
do {
printf("Input an int from [5, 25]");
scanf("%d", &n);
} while (n < 5 || n >= 25);
for (i=0; i < n; i++){
star += '*';
printf("%c", star);
}
return 0;
}
You cannot write star += '*'; because you declared star as a char, C is strongly typed, a char is a char not a table of char.
You have to use nested loop, like this for example:
#include <stdio.h>
int main(void)
{
int n, i, j;
char star = '*';
do
{
printf("Input an int from [5, 25]");
scanf("%d", &n);
} while (n < 5 || n >= 25);
for (i = 1; i <= n; i++)
{
for (j = 1; j <= i; j++)
{
printf("*");
}
printf("\n");
}
return 0;
}
You need nested loops
for (int i=0; i < n; i++)
{
for(int j = 0; j <= i; j++)
printf("*");
printf("\n");
}
or if you want to use strings:
char str[n + 1];
for (int i=0; i < n; i++)
{
str[i] = '*';
str[i + 1] = 0;
puts(str);
}
https://godbolt.org/z/aT8brP1ch
The statement
star += '*';
is not the correct way to concatenate two strings in C. In order to do this, you can define an array with sufficient space for the string and use the function strcat, like this:
#include <stdio.h>
#include <string.h>
int main(void)
{
int n;
//initialize "stars" to an empty string
char stars[20] = {0};
do {
printf("Input an int from [5, 25]: ");
scanf("%d", &n);
} while (n < 5 || n >= 25);
//build the string containing the stars using repeated
//string concatentation
for ( int i = 0; i < n; i++ ) {
strcat( stars, "*" );
}
//print the string
printf( "%s\n", stars );
return 0;
}
This program has the following behavior:
Input an int from [5, 25]: 5
*****
However, this is highly inefficient and unnecessarily complicated. Instead of first building the string in an array before printing it out all at once, it is usually easier to simply print it one character at a time:
#include <stdio.h>
#include <string.h>
int main(void)
{
int n;
do {
printf("Input an int from [5, 25]: ");
scanf("%d", &n);
} while (n < 5 || n >= 25);
//print the stars one character at a time
for ( int i = 0; i < n; i++ ) {
putchar( '*' );
}
//end the line
putchar( '\n' );
return 0;
}
This program has the same output as the first program.
You now have the solution for printing out a single line. However, your task involves printing out several lines. This will require a nested loop. In accordance with the community guidelines on homework questions, I will not provide the full solution at this time, as you should attempt to do this yourself, first.
char is an integral type - that is, it represents a number. '*' is a Character Constant, which actually has the type int.
char star = '*';
star += '*';
In ASCII, this is no different from
char star = 42;
star += 42;
A string is a series of nonzero bytes, followed by a zero byte (the null terminating character, '\0'). You cannot build a string by adding two integers together.
To build a string, you must place each byte in a buffer in sequence, and ensure a null terminating byte follows.
#include <stdio.h>
#define MIN 5
#define MAX 25
int main(void)
{
int n;
do {
printf("Input an int from [%d, %d): ", MIN, MAX);
if (1 != scanf("%d", &n)) {
fprintf(stderr, "Failed to parse input.\n");
return 1;
}
} while (n < MIN || n >= MAX);
char buffer[MAX + 1] = { 0 };
for (int i = 0; i < n; i++) {
buffer[i] = '*';
buffer[i + 1] = '\0';
puts(buffer);
}
}
Aside: never ignore the return value of scanf.
Or you can avoids strings, and just print the characters directly.
for (int i = 0; i < n; i++) {
for (int j = 0; j <= i; j++)
putchar('*');
putchar('\n');
}
#include <stdio.h>
#include <stdlib.h>
int main() {
int n,i,j;
printf("enter a number between 5 & 25");
scanf("%d",&n);
for(i=1;i<=n;i++){
for(j=1;j<=i;j++){
printf("*");
}
printf("\n");
}
return 0;
}
String concatenation does not work like that in C, instead use strcat().

Add strings to an array

The problem: After the convert_tolower(words) function is completed I want to add a new word in the words array( if the words array has less than 5 words)..But I am getting either errors or unexpected results(e.g some weird characters being printed)...What i thought is shifting the elements of the words array and then work with pointers because I am dealing with strings.But I am having quite some trouble achieving that..Probably the problem is in lines
35-37
How I want the program to behave:
Get 5 words(strings) at most from user input
Take these strings and place them in an array words
Convert the elements of the array to lowercase letters
After the above,ask the user again to enter a new word and pick the position of that word.If the words array already has 5 words then the new word is not added.Else,the new word is added in the position the user chose.(The other words are not deleted,they are just 'shifted').
Also by words[1] I refer to the first word of the words array in its entirety
The code:
#include <stdio.h>
#include <string.h>
#define W 5
#define N 10
void convert_tolower(char matrix[W][N]);
int main() {
int j = 0;
int i = 0;
int len = 0;
char words[W][N] = {{}};
char test[W][N];
char endword[N] = "end";
char newword[N];
int position;
while (scanf("%9s", test), strcmp(test, endword)) {
strcpy(words[i++], test);
j++;
len++;
if (j == W) {
break;
}
}
convert_tolower(words);
printf("Add a new word\n");
scanf("%9s", newword);
printf("\nPick the position\n");
scanf("%d",position);
if (len < W) {
for (i = 0; i < W-1; i++) {
strcpy(words[i], words[i + 1]); /*Shift the words */
words[position] = newword;
}
}
for (i = 0; i < W; i++) {
printf("%s", words[i]);
printf("\n");
}
printf("End of program");
return 0;
}
void convert_tolower(char matrix[W][N]) {
int i;
int j;
for (i = 0; i < W; i++) {
for (j = 0; j < N; j++) {
matrix[i][j] = tolower(matrix[i][j]);
}
}
}
This initialization
char words[W][N] = {{}};
is incorrect in C. If you want to zero initialize the array then just write for example
char words[W][N] = { 0 };
In the condition of the while loop
while (scanf("%9s", test), strcmp(test, endword)) {
there is used the comma operator. Moreover you are using incorrectly the two-dimensional array test instead of a one-dimensional array
It seems you mean
char test[N];
//...
while ( scanf("%9s", test) == 1 && strcmp(test, endword) != 0 ) {
And there are used redundantly too many variables like i, j and len.
The loop could be written simpler like
char test[N];
//...
for ( ; len < W && scanf("%9s", test) == 1 && strcmp(test, endword) != 0; ++len )
{
strcpy(words[len], test);
}
In this call
scanf("%d",position);
there is a typo. You must to write
scanf("%d", &position);
Also you should check whether the entered value of position is in the range [0, len].
For example
position = -1;
printf("\nPick the position\n");
scanf("%d", &position);
if ( len < W && -1 < position && position <= len ) {
Also this for loop
for (i = 0; i < W-1; i++) {
strcpy(words[i], words[i + 1]); /*Shift the words */
words[position] = newword;
}
does not make a sense. And moreover this assignment statement
words[position] = newword;
is invalid. Arrays do not have the assignment operator.
You need to move all strings starting from the specified position to the right.
For example
for ( i = len; i != position; --i )
{
strcpy( words[i], words[i-1] );
}
strcpy( words[position], newword );
++len;
And it seems the function convert_tolower should be called for the result array after inserting a new word. And moreover you need to pass the number of actual words in the array.
convert_tolower(words, len);
The nested loops within the function convert_tolower should look at least the following way
void convert_tolower(char matrix[][N], int n) {
int i;
int j;
for (i = 0; i < n; i++) {
for (j = 0; matrix[i][j] != '\0'; j++) {
matrix[i][j] = tolower(( unsigned char )matrix[i][j]);
}
}
}
The main problem with your code was initially that you declared char *words[W][N], then tried to insert strings into this 2d array of pointers. Sparse use of organizing functions, and variables with large scopes than necessary made it hard to read. I think the best way to help you is to show you a working minimal implementation. Step 4 is not sufficiently specified. insert currently shift. It is not clear what should happen if you insert at position after empty slots, or if insert a position before empty slots and in particular if there are non-empty slots after said position.
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#define W 5
#define N 10
void convert(size_t w, size_t n, char list[][n]) {
for(size_t i = 0; i < w; i++) {
for(size_t j = 0; j < n; j++) {
list[i][j] = tolower(list[i][j]);
}
}
}
void insert(size_t w, size_t n, char list[][n], size_t pos, char *word) {
// out out of bounds
if(pos + 1 > w) return;
// shift pos through w - 2 pos
for(size_t i = w - 2; i >= pos; i--) {
strcpy(list[i + 1], list[i]);
if(!i) break;
}
// insert word at pos
strcpy(list[pos], word);
}
void print(size_t w, size_t n, char list[][n]) {
for (size_t i = 0; i < w; i++) {
printf("%u: %s\n", i, list[i]);
}
}
int main() {
char words[W][N] = { "a", "BB", "c" };
convert(W, N, words);
insert(W, N, words, 0, "start");
insert(W, N, words, 2, "mid");
insert(W, N, words, 4, "end");
insert(W, N, words, 5, "error")
print(W, N, words);
return 0;
}
and the output (note: "c" was shifted out as we initially had 3 elements and added 3 new words with valid positions):
0: start
1: a
2: mid
3: bb
4: end

Why does my C code say char matches other char even tho it does?

I am making a simple hangman game in C, I am trying to check if each character in the string matches the guessed character. but when I test it, it gives results that are incorrect and shouldn't have passed the if statement in the first place. for example when I enter the letter a (The word is apple) it give me a__a. somehow the word became 4 letters long instead of 5 and it said that the last letter is a even tho it isn't.
https://imgur.com/a/DZDTbbj
#include <stdio.h>
int main() {
int size = 0;
char word[] = "apple", guess, hidden[size];
while (word[size] != '\0') {
size++;
}
for (int i = 0; i < size; ++i) {
hidden[i] = '_';
}
while (1) {
printf("%s\n", hidden);
scanf(" %c", &guess);
for (int y = 0; y < size; ++y) {
if (word[y] == guess) {
hidden[y] = guess;
}
}
}
return 0;
}
You declare hidden[size] before the loop that sets size to the length of word. So it's using the initial value 0 as the length of the array.
Move that declaration down to after the loop. Also, you need to make the length size+1 to allow room for the null terminator, and then add the null terminator.
int main()
{
int size=0;
char word[]="apple",guess;
while(word[size]!='\0'){
size++;
}
char hidden[size+1];
for (int i = 0; i < size; ++i)
{
hidden[i]='_';
}
hidden[size] = '\0';
while(1){
printf("%s\n",hidden );
scanf(" %c",&guess);
for (int y = 0; y < size; ++y)
{
if (word[y] == guess)
{
hidden[y]=guess;
}
}
}
return 0;
}

Numbers in char array printing as random characters

So I'm writing a somewhat simple C program that is supposed to take a string of characters separated by semicolons as input. The program is then supposed to sort the strings by length and print them to the console.
Ex: abc;12;def;1234
The issue I'm having is that any numbers that are entered end up being printed as random symbols and I'm not sure why. I'm taking in input in this function:
void get_strings(char** c)
{
while (scanf("%[^;]s", c[numStrings]) != EOF)
{
getchar();
numStrings += 1;
}
}
Since scanf is looking for strings, if numbers are entered, are they stored as the 'character form' of those numbers, or should I be casting somehow?
Here's the rest of the code:
int numStrings = 0;
void sort_strings(char** c)
{
for (int i = 0; i < numStrings; i++)
{
for (int j = 0; j < numStrings - i; j++)
{
if (strlen(c[j]) > strlen(c[j + 1]))
{
char temp[1000];
strcpy(c[j], temp);
strcpy(c[j + 1], c[j]);
strcpy(temp, c[j + 1]);
}
}
}
}
void show_strings(char** c)
{
for (int i = 0; i < numStrings; i++)
{
if (printf("%s\n", c[i]) != EOF) break;
}
}
int main()
{
char wordLen[100][1000];
char* word2[100];
for (int i = 0; i < 100; i++)
{
word2[i] = wordLen[i];
}
char** words = word2;
get_strings(words);
sort_strings(words);
show_strings(words);
return 0;
}
The parsing code is incorrect:
void get_strings(char **c) {
while (scanf("%[^;]s", c[numStrings]) != EOF) {
getchar();
numStrings += 1;
}
}
the scanf() format contains an extra s that does not match the input.
the return value of scanf() should be compared to 1 to ensure successful conversion. Conversion failure produces EOF only at end of file, otherwise it produces 0 and the contents of c[numStrings] will be indeterminate.
conversion stops at the first character ;, this character stays in the input stream, but it is read by getchar(), yet if there is an empty field, the corresponding conversion would fail and the contents of the array would be indeterminate.
you should not use a global variable for the number of strings read. You should instead return this number.
The sorting code is incorrect too:
the inner loop runs one index too far: j + 1 must be less than numStrings for all runs.
the arguments to strcpy are passed in the wrong order.
strcpy should not be used at all, you should just swap the pointers.
show_strings() always stops after the first line as printf will return the number of characters printed.
You can fix the reading loop this way:
#include <stdio.h>
#include <string.h>
int get_strings(char **c, int maxStrings) {
int numStrings = 0;
while (numStrings < maxStrings) {
switch (scanf("%999[^;]", c[numStrings])) {
case 1:
getchar();
numStrings += 1;
break;
case 0:
if (getchar() == ';') {
c[numStrings] = '\0';
numStrings += 1;
}
break;
case EOF:
return numStrings;
}
}
}
void sort_strings(char **c, int count) {
for (int i = 0; i < count; i++) {
for (int j = 0; j < count - i - 1; j++) {
if (strlen(c[j]) > strlen(c[j + 1])) {
char *temp = c[j];
c[j] = c[j + 1];
c[j + 1] = temp;
}
}
}
}
void show_strings(char **c, int count) {
for (int i = 0; i < count; i++) {
printf("%s\n", c[i]);
}
}
int main(void) {
char words[1000][100];
char *wordPtrs[100];
int numStrings;
for (int i = 0; i < 100; i++) {
wordPtrs[i] = words[i];
}
numStrings = get_strings(wordPtrs, 100);
sort_strings(wordPtrs, numStrings);
show_strings(wordPtrs, numStrings);
return 0;
}

String array prints out trash values

So I have an assignment where I should delete a character if it has duplicates in a string. Right now it does that but also prints out trash values at the end. Im not sure why it does that, so any help would be nice.
Also im not sure how I should print out the length of the new string.
This is my main.c file:
#include <stdio.h>
#include <string.h>
#include "functions.h"
int main() {
char string[256];
int length;
printf("Enter char array size of string(counting with backslash 0): \n");
/*
Example: The word aabc will get a size of 5.
a = 0
a = 1
b = 2
c = 3
/0 = 4
Total 5 slots to allocate */
scanf("%d", &length);
printf("Enter string you wish to remove duplicates from: \n");
for (int i = 0; i < length; i++)
{
scanf("%c", &string[i]);
}
deleteDuplicates(string, length);
//String output after removing duplicates. Prints out trash values!
for (int i = 0; i < length; i++) {
printf("%c", string[i]);
}
//Length of new string. The length is also wrong!
printf("\tLength: %d\n", length);
printf("\n\n");
getchar();
return 0;
}
The output from the printf("%c", string[i]); prints out trash values at the end of the string which is not correct.
The deleteDuplicates function looks like this in the functions.c file:
void deleteDuplicates(char string[], int length)
{
for (int i = 0; i < length; i++)
{
for (int j = i + 1; j < length;)
{
if (string[j] == string[i])
{
for (int k = j; k < length; k++)
{
string[k] = string[k + 1];
}
length--;
}
else
{
j++;
}
}
}
}
There is a more efficent and secure way to do the exercise:
#include <stdio.h>
#include <string.h>
void deleteDuplicates(char string[], int *length)
{
int p = 1; //current
int f = 0; //flag found
for (int i = 1; i < *length; i++)
{
f = 0;
for (int j = 0; j < i; j++)
{
if (string[j] == string[i])
{
f = 1;
break;
}
}
if (!f)
string[p++] = string[i];
}
string[p] = '\0';
*length = p;
}
int main() {
char aux[100] = "asdñkzzcvjhasdkljjh";
int l = strlen(aux);
deleteDuplicates(aux, &l);
printf("result: %s -> %d", aux, l);
}
You can see the results here:
http://codepad.org/wECjIonL
Or even a more refined way can be found here:
http://codepad.org/BXksElIG
Functions in C are pass by value by default, not pass by reference. So your deleteDuplicates function is not modifying the length in your main function. If you modify your function to pass by reference, your length will be modified.
Here's an example using your code.
The function call would be:
deleteDuplicates(string, &length);
The function would be:
void deleteDuplicates(char string[], int *length)
{
for (int i = 0; i < *length; i++)
{
for (int j = i + 1; j < *length;)
{
if (string[j] == string[i])
{
for (int k = j; k < *length; k++)
{
string[k] = string[k + 1];
}
*length--;
}
else
{
j++;
}
}
}
}
You can achieve an O(n) solution by hashing the characters in an array.
However, the other answers posted will help you solve your current problem in your code. I decided to show you a more efficient way to do this.
You can create a hash array like this:
int hashing[256] = {0};
Which sets all the values to be 0 in the array. Then you can check if the slot has a 0, which means that the character has not been visited. Everytime 0 is found, add the character to the string, and mark that slot as 1. This guarantees that no duplicate characters can be added, as they are only added if a 0 is found.
This is a common algorithm that is used everywhere, and it will help make your code more efficient.
Also it is better to use fgets for reading input from user, instead of scanf().
Here is some modified code I wrote a while ago which shows this idea of hashing:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define NUMCHAR 256
char *remove_dups(char *string);
int main(void) {
char string[NUMCHAR], temp;
char *result;
size_t len, i;
int ch;
printf("Enter char array size of string(counting with backslash 0): \n");
if (scanf("%zu", &len) != 1) {
printf("invalid length entered\n");
exit(EXIT_FAILURE);
}
ch = getchar();
while (ch != '\n' && ch != EOF);
if (len >= NUMCHAR) {
printf("Length specified is longer than buffer size of %d\n", NUMCHAR);
exit(EXIT_FAILURE);
}
printf("Enter string you wish to remove duplicates from: \n");
for (i = 0; i < len; i++) {
if (scanf("%c", &temp) != 1) {
printf("invalid character entered\n");
exit(EXIT_FAILURE);
}
if (isspace(temp)) {
break;
}
string[i] = temp;
}
string[i] = '\0';
printf("Original string: %s Length: %zu\n", string, strlen(string));
result = remove_dups(string);
printf("Duplicates removed: %s Length: %zu\n", result, strlen(result));
return 0;
}
char *remove_dups(char *str) {
int hash[NUMCHAR] = {0};
size_t count = 0, i;
char temp;
for (i = 0; str[i]; i++) {
temp = str[i];
if (hash[(unsigned char)temp] == 0) {
hash[(unsigned char)temp] = 1;
str[count++] = str[i];
}
}
str[count] = '\0';
return str;
}
Example input:
Enter char array size of string(counting with backslash 0):
20
Enter string you wish to remove duplicates from:
hellotherefriend
Output:
Original string: hellotherefriend Length: 16
Duplicates removed: helotrfind Length: 10

Resources