rearranging a char array with strncpy in C - c

I am trying to change the sorting of a the arr list which could consist of zero, one, two as the inputted and stored values for arr. The stringreplace function is meant to shift every single element by one so the new sorting would be one, two, zero. I am trying to replace the elements with one another by using the strncpy function but I think it is a bit faulty, how could i fix this?
strncpy function
char stringreplace( char a[], int b){
for(int j = 0; j > b -1; j++){
strncpy(a[j], a[j+1], sizeof(a));}
for(int j = 0; j > b; j++){
printf("%s",a[j]);}
}
main function
int main()
{
char input[100];
char arr[100]= {0};
int number;
printf("Input the number of strings: ");
scanf("%d", &number);
for(int i= 0; i < number; i++){
printf("Input the number of strings: ");
scanf("%s", input);
arr[i] = input;
}
stringreplace(arr, number);
return 0;
}

You may consider allocating strings dynamically, assigning a pointer for each string into an array words, and then rotating each pointer in the array to the left.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void lrot_words(char *words[], int n);
int main(void)
{
char *p, word[100], *words[100];
int i, num_words;
printf("Enter the number of words: ");
scanf("%d", &num_words);
for(i = 0; i < num_words; i++){
printf("Enter a word: ");
scanf("%s", word);
if ((p = malloc(strlen(word) + 1)) == NULL) {
fprintf(stderr, "Error: malloc failed\n");
exit(EXIT_FAILURE);
}
words[i] = strcpy(p, word);
}
lrot_words(words, num_words);
for (i = 0; i < num_words; i++) {
printf("%s\n", words[i]);
}
return 0;
}
void lrot_words(char *words[], int n)
{
char *temp = words[0];
int i;
for (i = 0; i < n - 1; i++) {
words[i] = words[i+1];
}
words[i] = temp;
}

Related

Need some help how to enter a number and count it using array

I have to code in an array that can count an element. For example, if the user enters a 2, 2, 2, 1,1 then the user wants to count the number 2 then the result will be ELEMENT is 2 and FREQUENCY is 3. but I have a problem with the parts of " ENTER THE NUMBER YOU WANT TO BE COUNTED". I use scanf but when I run it I cannot enter any number.
Here's my code:
void frequency()
{
system("cls");
int num;
int count=0;
printf("Enter a number you want to be count: \n ");
scanf("i%", &num);
printf(" ELEMENT | FREQUENCY \n ");
for (i = 0; i<=n; i++)
{
if (a[i]==a[num])
count++;
}
printf(" \n %i ", num);
printf(" \t\t");
printf("%i \n ", count);
getch();
}
Your program requires understanding on two parts:
Get input and split input by delimiter, which can be done by using strtok.
Algorithm for finding the duplicated elements in an array.
#include <stdio.h>
#include <string.h>
int main() {
frequency();
return 0;
}
void frequency() {
char str[100];
printf("Enter a number you want to be count: \n ");
gets(str);
int init_size = strlen(str);
char delim[] = " ";
char *ptr = strtok(str, delim);
char *pch;
int arr[20];
int count = 0;
int ncount, i, j;
int a[count], Freq[count];
while(ptr != NULL) {
/*printf("'%s'\n", ptr);*/
/*Converts the string argument str to an integer (type int)*/
arr[count] = atoi(ptr);
/*strtok accepts two strings - the first one is the string to split, the second one is a string containing all delimiters*/
ptr = strtok(NULL, delim);
/*Initialize frequency value to -1*/
Freq[count] = -1;
count += 1;
}
/*Count the frequency of each element*/
for (i = 0; i < count; i++) {
ncount = 1;
for(j = i + 1; j < count; j++) {
/*Part to perform checking for duplicate elements*/
if(arr[i] == arr[j]) {
ncount++;
/*Make sure not to count frequency of same element again*/
Freq[j] = 0;
}
}
/*If frequency of current element is not counted*/
if(Freq[i] != 0) {
Freq[i] = ncount;
}
}
printf(" ELEMENT | FREQUENCY \n");
printf("-------------------------\n");
for (i = 0; i < count; i++) {
if(Freq[i] != 0) {
printf("\t%d\t\t\t%d\n", arr[i], Freq[i]);
}
}
}
Also, from your code:
You did not define i and n, which is required by your for loop. Also, since your for loop is for (i = 0; i<=n; i++), you have to define the value of n, which is the length of elements inputted by the user, in order to loop through the number of elements you expected.
int i, n, num;
...
...
for (i = 0; i<=num; i++)
Your scanf("i%", &num); should be scanf("%i", &num); instead.
You did not initialize your array a. You should have this line of code before assigning values to your array a. The value 20 can be adjusted by yourself depending on how many inputs are expected. Also, it can be coded in a flexible way instead of hardcoded as 20.
...
int i, num;
int count=0;
int a[20];
...
...
Lastly, it is a good practice to include the function's library before using it. In your case, you should include #include <conio.h> to use the getch() function.

Dynamically allocate an array of strings

How can I fix this code in a way that it prints the words in the array? Moreover this is the right way to dynamically allocate memory for n words of max size 40?
int main() {
int n;
char *arr;
int i;
printf("Give me a number:");
scanf("%d", &n);
arr = malloc(n * 40);
for (i = 0; i < n; i++)
{
printf("Give me a word: ");
scanf("%s", &arr[i]);
}
for (i = 0; i < n; i++)
{
printf("%s", arr[i]); //< --problem here
}
return 0;
}
Your allocation is not the best, and printf argument arr[i] expects a char* but you pass it an int (a char if you'd like).
Here is how you should do it, with comments:
Live demo
#include <stdio.h>
#include <stdlib.h> //for malloc
int main(){
int n;
int i;
printf("Give me a number:");
scanf("%d", &n);
//declare a variable of pointer to pointer to char
//allocate memory for the array of pointers to char,
//each one capable of pointing to a char array
char **arr = malloc(n * sizeof *arr);
if(arr == NULL){ //check for allocation errors
perror("malloc");
return EXIT_FAILURE;
}
//allocate memory for each individual char array
for(i = 0; i < n; i++){
arr[i] = malloc(40); //char size is always 1 byte
if(arr == NULL){ //check for allocation errors
perror("malloc");
return EXIT_FAILURE;
}
}
for (i = 0; i < n; i++){
printf("Give me a word: ");
//limit the size of read input to 39 charaters to avoid overflow,
//a nul character will be added by scanf
scanf("%39s", arr[i]);
}
for (i = 0; i < n; i++){
printf("%s\n", arr[i]);
}
for(int i = 0; i < n; i++){ //free the memory for each char array
free(arr[i]);
}
free(arr); //free array of pointers
return 0;
}
You can also do this with less code using a pointer to array of 40 chars, this will simplify the memory allocation and deallocation:
Sample with comments:
Live demo
#include <stdio.h>
#include <stdlib.h> //for malloc
int main(){
int n;
int i;
printf("Give me a number:");
scanf("%d", &n);
//declare a pointer to array of chars and
//allocate memory for all the char arrays
char (*arr)[40] = malloc(n * sizeof *arr);
if(arr == NULL){ //check for allocation errors
perror("malloc");
return EXIT_FAILURE;
}
for (i = 0; i < n; i++){
printf("Give me a word: ");
scanf("%39s", arr[i]);
}
for (i = 0; i < n; i++){
printf("%s\n", arr[i]);
}
free(arr); //free allocated memory
return 0;
}
This:
for(i=0;i<n;i++){
printf("Give me a word: ");
scanf("%s",&arr[i]);
}
is probably not what you want.
You probably want this instead:
for(i=0; i<n; i++){
printf("Give me a word: ");
scanf("%s", arr + i*40);
}
then later:
for(i=0; i<n; i++){
printf("%s", arr + i*40);
}
Remember that a string in C is just an array of characters.
Thus when defining char *arr, you are creating a single string. Had you done char **arr it would have been an array of strings, which is what you want.
However, I find that allocating/freeing arrays of arrays on the heap to be rather inconvenient, and prefer 'flattening' them into a single array.
This is exactly what you were doing with arr = malloc(n*40), but then later you treated this array of characters as an array of strings when you did this:
for(i=0; i<n; i++){
printf("Give me a word: ");
scanf("%s", &arr[i]);
}
Note that this is actually perfectly legal (scanf wanted a char* and you gave it one), but it's a logical error since you are giving it the n-th character when you wanted to give it the n-th array.
And oh yes, don't forget to free(arr) later.

Character Array User Input Scanf

Just started learning programming on my own and whilst trying to create an array of characters from user input, using scanf, have hit the wall; the code is as below:
#include <stdio.h>
#define I 5
int main (void) {
char a[I+1] = {a[I+1] = '\0'}, q;
int i;
for(i = 0; i < I; i++) {
printf("Enter an alphabet:\t");
//scanf("%c", &q);
//scanf("%c*\n", &q);
//scanf("%[^\n]", &q);
//scanf("%[a-z, A-Z]", &q);
scanf("%127[^\n]", &q);
a[i] = q;
}
printf("\n");
for(i = 0; i < I; i++) {
printf("Element a[%d] of a[I]:\t%c\n", i, a[i]);
}
printf("And the a[I] string:\t%s\n", a);
return 0;
}
None of the scanf combinations in the above code works: the program either skips input prompt after the first one or does not store response.
How can this be resolved with scanf?
char a[I+1] = {a[I+1] = '\0'} is not valid. Even if it compiles, it is going out of bounds when assigning the '\0' character. The commonly used convention looks more like this instead:
char a[I+1] = {0};
Or simply:
char a[I+1] = {};
That said, q is only 1 char in size, but your scanf() is trying to read a string up to 127 chars into q. So you are going to trash memory. To read a single char at a time, use %c instead:
#include <stdio.h>
#include <string.h>
#define MAX_INPUT 5
int main (void) {
char a[MAX_INPUT+1];
int i, len;
for(i = 0; i < MAX_INPUT; i++) {
printf("Enter an alphabet:\t");
scanf("%c", &a[i]);
}
a[MAX_INPUT] = '\0';
printf("\n");
len = strlen(a);
for(i = 0; i < len; i++) {
printf("Element a[%d]:\t%c\n", i, a[i]);
}
printf("And the a string:\t%s\n", a);
return 0;
}
Or, you can remove the loop and just use a single call to scanf() using "%5[^\n]" as the format string:
#include <stdio.h>
#include <string.h>
#define MAX_INPUT 5
int main (void) {
char a[MAX_INPUT+1];
char fmt[20];
int i, len;
sprintf(fmt, "%%%d[^\n]", MAX_INPUT);
printf("Enter an alphabet:\t");
scanf(fmt, a);
printf("\n");
len = strlen(a);
for(i = 0; i < len; i++) {
printf("Element a[%d]:\t%c\n", i, a[i]);
}
printf("And the a string:\t%s\n", a);
return 0;
}
This works without any warning or error on Cygwin gcc v7.3 with Wall flag:
#include <stdio.h>
#define I 5
int main (void) {
char a[I+1] = {a[I+1] = '\0'},q;
int i;
for(i = 0; i < I; i++) {
printf("Enter an alphabet:\t");
scanf("%c%*c", &q);
a[i] = q;
}
printf("\n");
for(i = 0; i < I; i++) {
printf("Element a[%d] of a[I]:\t%c\n", i, a[i]);
}
printf("And the string a[I]:\t%s\n", a);
return 0;
}

Why I can't input my name with gets?

Here's the part of my code:
Problem: It skips the input of "please enter your name" to "please enter your marks"
What I tried: flushall(); _flushall(); - which worked yesterday somehow, and trying to place these functions between printf,scanf..
student *Create_Class(int size) {
int i, j;
int idStud, nameStud, markStud;
student *classStudent;
classStudent = (student*)malloc(size * sizeof(student));
for (i = 0; i < size; i++) {
classStudent[i].name = (char*)malloc(51 * sizeof(char));
int numOfmarks = 4;
printf("Please enter your name: ");
gets(classStudent[i].name);
_flushall(); //tried _flushall() and it worked yesterday.. tried fflush(NULL) too.
printf("\nPlease enter 4 marks: ");
for (j = 0; j < numOfmarks; j++) {
scanf("%d", &classStudent[i].marks[j]);
}
Avg_Mark(&classStudent[i]);
}
return classStudent;
}
EDIT: (FULL CODE)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
typedef struct {
char *name;
int marks[4];
float avg;
} student;
student *Create_Class(int);
void Avg_Mark(student*);
void Print_One(student*);
void exStudents(student *s, int size);
int main() {
int size, i;
student *arr;
printf("\nEnter the number of students: \n");
scanf("%d", &size);
arr = Create_Class(size);
exStudents(arr, size);
for (i = 0; i < size; i++)
free(arr[i].name);
free(arr);
getch();
}
student *Create_Class(int size) {
int i, j;
int idStud, nameStud, markStud;
student *classStudent;
classStudent = (student*)malloc(size * sizeof(student));
for (i = 0; i < size; i++) {
classStudent[i].name = (char*)malloc(51 * sizeof(char));
int numOfmarks = 4;
int sizeOfName;
printf("Please enter your name: \n");
_flushall();
fgets(classStudent[i].name,50,stdin);
sizeOfName = strlen(classStudent[i].name);
printf("Please enter 4 marks: ");
for (j = 0; j < numOfmarks; j++) {
scanf("%d", &classStudent[i].marks[j]);
}
Avg_Mark(&classStudent[i]);
}
return classStudent;
}
void Avg_Mark(student *s) {
int i, numOfMarks = 4, sum = 0;
for (i = 0; i < numOfMarks; i++) {
sum += s->marks[i];
}
s->avg = (sum / 4.0);
}
void Print_One(student *s) {
printf("The average of %s is %f", s->name, s->avg);
}
void exStudents(student *s, int size) {
int flag = 1;
while (size > 0) {
if (s->avg > 85) {
Print_One(s);
flag = 0;
}
s++;
size--;
}
if (flag)
printf("\n There're no students with above 85 average.");
}
As you have already been told in comments, the solution is to use a two-step approach: Read lines first, then scan these lines as appropriate. This reflects how users are going to answer your prompts, namely by providing the information and then hitting enter.
Here's a variant of your code which does that. I've also changed the main function, because it also used scanf and I've added a function to strip white space from the string input by fgets. (This function requires the <ctype.h> header.)
#include <ctype.h>
int main()
{
char line[80];
int size, i;
puts("Enter the number of students:");
if (fgets(line, sizeof(line), stdin) == NULL) exit(1);
if (sscanf(line, "%d", &size) == 1 && size > 0) {
student *arr = Create_Class(size);
exStudents(arr, size);
for (i = 0; i < size; i++) free(arr[i].name);
free(arr);
}
return 0;
}
/*
* strip white space from beginning and end of string
*/
char *strip(char *str)
{
size_t l = strlen(str);
while (l > 0 && isspace((unsigned char) str[l - 1])) l--;
str[l] = '\0';
while (isspace((unsigned char) *str)) str++;
return str;
}
/*
* Create students and prompt user for input
*/
student *Create_Class(int size)
{
int i;
student *classStudent = malloc(size * sizeof(student));
for (i = 0; i < size; i++) {
char line[80];
char *p;
int okay = 0;
puts("Please enter your name:");
if (fgets(line, sizeof(line), stdin) == NULL) exit(1);
p = strip(line);
classStudent[i].name = malloc(strlen(p) + 1);
strcpy(classStudent[i].name, p);
while (!okay) {
int j = 0;
okay = 1;
puts("Please enter 4 marks:");
if (fgets(line, sizeof(line), stdin) == NULL) exit(1);
p = line;
while (p && j < 4) {
char *tail;
int m = strtol(p, &tail, 10);
if (p == tail) break;
if (m < 1 || m > 100) {
puts("Illegal mark.");
okay = 0;
}
classStudent[i].marks[j++] = m;
p = tail;
}
if (j < 4) {
printf("Expected 4 marks, but got %d.\n", j);
okay = 0;
}
}
Avg_Mark(&classStudent[i]);
}
return classStudent;
}
Please refrain from flushing buffers wihout reason. When a new-line character is written, stdout is flushed, so make it a rule to terminate all your strings with a new-line. New-lines at the beginning of strings instead of at the end are a sign of untidy output.
SOLUTION:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
typedef struct { //struct decleration
char *name;
int marks[4];
float avg;
} student;
//functions decleration
student *Create_Class(int);
void Avg_Mark(student*);
void Print_One(student*);
void exStudents(student *s, int size);
int main() {
/*variable declerations*/
int i, size;
char line[80];
student *arr;
/*Input number of students*/
printf("\nEnter the number of students: \n");
fgets(line, sizeof(line), stdin);
sscanf(line, "%d", &size);
/*Get name of students, marks, and calculate average above 85*/
arr = Create_Class(size);
exStudents(arr, size);
/*Free memory*/
for (i = 0; i < size; i++)
free(arr[i].name);
free(arr);
getch();
}
student *Create_Class(int size) { /*Get names of each student, and their 4 marks.*/
/*Variable declerations*/
int i, j;
char line[51];
student *classStudent;
/*Dynamic allocation to assign structure to every student*/
classStudent = (student*)malloc(size * sizeof(student));
/*Get name of students and their 4 marks*/
for (i = 0; i < size; i++) {
/*Variable decleration and dynamic allocation of 51 chars*/
classStudent[i].name = (char*)malloc(51 * sizeof(char));
int numOfmarks = 4;
int sizeOfName;
/*Input name of student*/
printf("Please enter your name: \n");
scanf("%s", classStudent[i].name);
/*Input marks of student*/
printf("Please enter 4 marks: ");
for (j = 0; j < numOfmarks; j++) {
scanf("%d", &classStudent[i].marks[j]);
}
/*Calculate average, and print averages of students above 85*/
Avg_Mark(&classStudent[i]);
}
return classStudent;
}
/*Calculate averages of students*/
void Avg_Mark(student *s) {
int i, numOfMarks = 4, sum = 0;
for (i = 0; i < numOfMarks; i++) {
sum += s->marks[i];
}
s->avg = (sum / 4.0);
}
/*Print average (if bigger than 85)*/
void Print_One(student *s) {
printf("The average of %s is %0.1f\n", s->name, s->avg);
}
/*Check whether the average is bigger than 85*/
void exStudents(student *s, int size) {
int flag = 1; //flag to check if there are any students with avg above 85
while (size > 0) {
if (s->avg > 85) {
Print_One(s); //Print the average
flag = 0; //We found atleast one student with avg > 85
}
s++; //Advance to next student
size--;
}
if (flag)
printf("\n There're no students with above 85 average.");
}
The problem in your code is that scanf does not consume the new-line returned by the user in:
scanf("%d", &size);
So when the program reaches:
fgets(classStudent[i].name,50,stdin);
the remaining new-line in stdin is received before the user can type anything.
A solution is to replace the initial scanf call by fgets and atoi calls.
char size_str[5];
fgets(size_str,5,stdin);
size = atoi(size_str);
A combination of fgets and sscanf also works also fine in general to first process user inputs and then convert it.
The variant with sscanf is:
char size_str[5];
fgets(size_str,5,stdin);
sscanf(size_str,"%d\n",&size);
Note that it might be safe to stop the program if the value entered is too large. Here we allow from 0 up to 999.
Note also that you have to do the same change some lines below.
instead of:
scanf("%d", &classStudent[i].marks[j]);
write:
char mark_str[5];
fgets(mark_str,5,stdin);
sscanf(mark_str,"%d\n",&classStudent[i].marks[j]);
Hope this helps.

Arranging a character array using bubble sort

Here is my code so far. I am perfectly able to sort files holding numbers but clueless when it comes to characters. It takes in a file of my choosing and outputs another file with the sorted array. But so far all I'm getting are blank files and I can't figure out why.
So how can I fix my code to sort an array of characters and then output it?
#include <stdio.h>
int bubble_sort(char *a, int n);
int main(void) {
char a[10];
int n = sizeof a / sizeof a[10];
int i;
char inname;
char outname;
printf("Enter input name: ");
scanf("%s", &inname);
printf("Enter output name: ");
scanf("%s", &outname);
FILE *in, *out;
out = fopen(&outname, "w");
if ((in = fopen(&inname, "r")) == NULL) {
printf("File not found\n");
}
else {
for (int i = 0; i < 10; i++)
{
fscanf(in, "%s ", &a[i]);
}
bubble_sort(a, n);
for (i = 0; i < 10; i++) {
printf("%s\n", a[i]);
fprintf(out, "%s\n", a[i]);
}
}
fclose(in);
fclose(out);
return 0;
}
int bubble_sort(char *a, int n) {
int i, j;
char temp;
for (j = 1; j<n; j++)
{
for (i = 0; i<n - j; i++)
{
if ((int)a[i] >= (int)a[i + 1])
{
temp = a[i];
a[i] = a[i + 1];
a[i + 1] = temp;
}
}
}
return a[i];
}
The basic problem, as I can see, is with
scanf("%s", &inname);
In your code, inname is a single char, which cannot hold string inputs. You'll be needing an array.
You need to change
char inname;
char outname;
to
#define NAMSIZ 32
char inname[NAMSIZ] = {0};
char outname[NAMSIZ] = {0};
and then,
scanf("%31s", inname);
and accordingly.
Same problem exist with fscanf(in, "%s ", &a[i]);, too.

Resources