safe user input (of any kind) in another array - c

I have some troubles with a small programm.
There should be inputs by the user (of different type). But when the user puts in a ZERO ("0") the loop should stop and the programm should print all inputs before zero.
If the do-while loop has finished I'd like to go through the array and print all inputs
So i tried to safe all inputs into another array. Unfortunately my problem is, that i cannot safe the input (scanf) into another array. I hope you can help me.
Here is the code:
int *iarray(unsigned int n) {
char input[MAX];
char key[] = "0";
char arr[MAX] //troublemaker
int i = 0;
int *iptr = malloc(n * sizeof(*iptr)); // or iptr = (int*) malloc(n * sizeof(int));
if (iptr != NULL) {
do {
i++;
printf("Geben sie Strings ein: ");
scanf("%s", input);
printf("%s\n", input);
/*
arr[i] = *input;
Here is the problem
*/
// i'd like to safe var input in another array for example arr[] and print it after the do- while loop
} while(strcmp(input, key) != 0); // compare if input = 0. -> if input zero then break
printf("Durchläufe %d\n", i);
}
return iptr;
}

I finally got the solution for my code, here we go. I would greatly appreciate any suggestion to improve my code. Cheers ;)
#define MAX 100
int *iarray(unsigned int n) {
char input[MAX][MAX];
char temp[MAX][MAX];
char key[] = "0";
int i = 0;
int *iptr = malloc(n * sizeof(*iptr)); // or iptr = (int*) malloc(n * sizeof(int));
if (iptr != NULL) {
do {
i++;
printf("Put in a strin: ");
scanf("%s", input[i]);
printf("%s\n", input[i]);
strcat(temp[i],input[i]); // i use a temp array to safe all input stings there
} while(strcmp(input[i], key) != 0); // compare if input = 0. -> if input zero then break
printf("Durchläufe %d\n", i);
int l;
for (int k = 1; k <= i; k++) { //first loop creates amount of input strings
printf("\n");
for (l = 0; temp[l] != NULL; l++) { // second loop prints every single letter
if (temp[k][l] == 0) { // if there is no if-statement i get a lot of crap from the output
break;
}else{
printf("%c" , temp[k][l]); // here i print my 2d arrays
}
}
printf(" -> lenght %d", l);
}
printf("\n");
}
return iptr;
}
...

you could try sprintf(arr, "%s %s", arr, input).
At the end of the while you will have the arr[] with all the input

Related

C Problem with counting elements in the list of names

I have made one program, where you enter a few characters (10 max). It makes you a list, count average length of surnames, tell about how much different names. But the problem is, when I enter the last number (10) - it sorts me it incorrectly (like 39399349349, 3443993). Beneath I will present my code. I am newbie in C, so please don't shut on me) I am convinced that sorting function is incorrect, but don't know what exactly(
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct people {
int num[10];
char surname[20];
char name[10];
} peoples[10], c;
int compare_people_num(const void *a, const void *b);
int main()
{
int i, j, k = 0, l = 0, m = 0, n = 0;
float s = 0;
char str[100];
system("chcp 1251 > nul");
for (i = 0, j = 0; i < 10; i++, j++)
{
printf("Enter number, surname, name %d of your human: ", i + 1);
fgets(str, sizeof str, stdin);
sscanf(str, "%d %s %s", &peoples[j].num, &peoples[j].name, &peoples[j].name);
while (str[n] != '\n')
{
if (str[n] != ' ')
{
peoples[j].num[k] = str[n];
}
else
break;
n++;
k++;
}
n++;
k = 0;
while (str[n] != '\n')
{
if (str[n] != ' ')
{
peoples[j].surname[k] = str[n];
}
else
break;
n++;
k++;
}
n++;
k = 0;
while (str[n] != '\n')
{
if (str[n] != '\0')
{
peoples[j].name[k] = str[n];
}
else
break;
n++;
k++;
}
n = 0;
k = 0;
}
for (i = 0; i < 10; i++)
{
for (j = i + 1; j < 10; j++)
{
if (!strcmp(peoples[i].name, peoples[j].name))
m = 1;
}
if (m == 0)
l++;
m = 0;
s = s + strlen(peoples[i].surname);
}
for (i = 0; i < 9; i++)
for (j = 0; j < 9; j++)
if (strcmp(peoples[j].num, peoples[j+1].num) > 0)
{
qsort(peoples, 10, sizeof(struct people), &compare_people_num);
}
for (i = 0; i < 10; i++)
{
printf("%d ", peoples[i].num);
printf("%s ", peoples[i].name);
printf("%s ", peoples[i].surname);
printf("\n");
}
printf("\nYou have %d different names\n", l);
printf("Avarege lenght of surname is = %f\n", s / 10);
}
int compare_people_num(const void *a, const void *b)
{
const struct people *p1 = a;
const struct people *p2 = b;
return p1->num - p2->num; // Change order to reverse sort
}
I went through your code and removed things that weren't needed. In both your input and sorting, it seemed like you were doing things twice. I tried to document the changes I made and explain why they should be made.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// It's generally a good idea to use #define when you have some global constants
// I made some of the constants larger than what you showed to prevent issues
#define MAX_NAME_LEN 40
#define MAX_SURNAME_LEN 40
#define NUM_PEOPLE 10
#define BUFF_LEN 100
// Separate your struct...
struct person {
int num;
char name[MAX_NAME_LEN];
char surname [MAX_SURNAME_LEN];
};
// ... and array decleration
static struct person people[NUM_PEOPLE];
// I added this function, to make it easier to display a person
void print_person (const struct person * p) {
printf("Person %d %s %s\n", p->num, p->name, p->surname);
}
// This function will print out every person in the people array
void print_people (void) {
for (int i=0; i<NUM_PEOPLE; i++) {
print_person(&people[i]);
}
}
// Compares two people by number
int compare_people_num (const void * a, const void * b) {
struct person * p0 = (struct person *) a;
struct person * p1 = (struct person *) b;
return p0->num - p1->num;
}
// Compares two people by name
int compare_people_name (const void * a, const void * b) {
struct person * p0 = (struct person *) a;
struct person * p1 = (struct person *) b;
return strcmp(p0->name, p1->name);
}
int main (void) {
int i;
char buffer[BUFF_LEN];
for (i=0; i<NUM_PEOPLE; i++) {
printf("Enter number, surname, and name of person %d: ", i+1);
fflush(stdout); // fflush makes sure that our text is shown to the user
fgets(buffer, BUFF_LEN, stdin); // Read user input in to buffer
// It's unclear what you were doing here
// This sscanf line takes a line of text, and splits it into a number and two words
// It then stores that number in people[i].num, and stores the words in name and surname
// However, right after this, you have several while loops that appear to be manually doing the same
// thing all over again. If you want to read all of the input in, just the line below is enough
sscanf(buffer, "%d %s %s", &people[i].num, people[i].name, people[i].surname);
}
// We've read all of the people in now
// Uncomment the next line to check out the output at this state:
// print_people();
// To count names, we first need to sort the people by their name
// We do this using a qsort call
qsort(people, NUM_PEOPLE, sizeof(struct person), compare_people_name);
// Once the names are sorted, we'll calculate how many different names there are
// We start the count at 1, and start checking from the second person (index 1)
// This is because the first person will always be unqiue, and we can't compare to
// person negative 1
int n_names = 1;
for (i=1; i<NUM_PEOPLE; i++) {
char * current = people[i].name;
char * previous = people[i-1].name;
if (!strcmp(current, previous)) {
n_names ++;
}
}
// Now we have to sort the people based on their num field
// Again, in your code, it looked like you were doing this more than nessecary
// We just have to call qsort once, as such
qsort(people, NUM_PEOPLE, sizeof(struct person), compare_people_num);
// We will also do a loop through to calculate the average surname length
float avg_surname_len = 0;
for (i=0; i<NUM_PEOPLE; i++) {
avg_surname_len += (float)strlen(people[i].surname);
}
avg_surname_len /= (float)NUM_PEOPLE;
// We're all done! The people are sorted by number.
print_people();
printf("There are %d unique names\n", n_names);
printf("The average surnames is %f characters\n", avg_surname_len);
}

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.

C program function to replace one word with another

I am very confused to create a function which will print a string and ask user to enter two numbers and then function will replace those number of words with one another.
I have added the image below as sample.
enter image description here
This is my homework, I have created other 3 functions, but don't really get this one.
Could somebody please help me how can I convert the words into numbers and then replace those number of words with one another.
This is my program it can break the string into words but how can i replace position of words.
#include <stdio.h>
#include <string.h>
int main()
{
char str1[100];
char newString[10][10];
int i,j,ctr;
printf("\n\n Split string by space into words :\n");
printf("---------------------------------------\n");
printf(" Input a string : ");
fgets(str1, sizeof str1, stdin);
j=0; ctr=0;
for(i=0;i<=(strlen(str1));i++)
{
// if space or NULL found, assign NULL into newString[ctr]
if(str1[i]==' '||str1[i]=='\0')
{
newString[ctr][j]='\0';
ctr++; //for next word
j=0; //for next word, init index to 0
}
else
{
newString[ctr][j]=str1[i];
j++;
}
}
printf("\n Strings or words after split by space are :\n");
for(i=0;i < ctr;i++)
printf(" %s\n",newString[i]);
return 0;
}
Seems to me that you are doing pretty good so far (your code can't handle comma but you can add that later). So let's assume that your newString actually contains the individual words.
So your next step is to construct a new string str2 from the individual words you have in newString. While you do that you can simply swap the two words of interest. To build the new string the strcat function could be helpful.
The code below is not fully correct but it may give you some ideas for getting on with your homework:
int lowest_index_to_swap = some_number
int highest_index_to_swap = some_higher_number
char str2[100] = "";
for (i=0; i<number_of_words_found; ++i)
{
if (i == lowest_index_to_swap)
strcat(str2, newString[highest_index_to_swap];
else if (i == highest_index_to_swap)
strcat(str2, newString[lowest_index_to_swap];
else
strcat(str2, newString[i];
strcat(str2, " ";
}
Here is code snippet what I tried in my local server based on your input in image.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define SIZE 100
#define WORDLEN 20
int main() {
int place_1, place_2, count = 0, i, k =0;
char str[] = "Hi, welcome to C programming";
char **words = (char **)malloc(sizeof(char *)*SIZE);
if(!words){
printf("malloc of words failed!\n");
exit(1);
}
char *temp = (char *)malloc(sizeof(char)*WORDLEN);
if(!temp){
printf("malloc of temp failed!\n");
exit(1);
}
for(i = 0; str[i] != '\0'; count++){
words[count] = (char *)malloc(sizeof(char)*WORDLEN);
if(!words[count]){
printf("malloc of words[%d] failed!\n", count);
exit(1);
}
sscanf(str+i, "%s", words[count]);
i += 1+strlen(words[count]);
printf("%d %s %d\n", count, words[count], i);
}
printf("Enter the word places to replace: ");
if(scanf("%d %d", &place_1, &place_2) < 2){
printf("scanf failed!\n");
exit(1);
}
temp = words[place_1 - 1];
words[place_1 - 1] = words[place_2 - 1];
words[place_2 - 1] = temp;
for(i = 0; i < count; i++){
sprintf(str+k, "%s ", words[i]);
k += 1+strlen(words[i]);
}
printf("str: %s\n", str);
free(temp);
for(i = 0; i < count; i++){
free(words[i]);
}
free(words);
}
Hope it helps.

Segmentation Fault: 11 C sometimes

I'm trying to run a program in C on my mac that asks the user to input a set of names. The program then sorts and capitalizes all the names and prints them capitalized and sorted. It then allows the user to search for a name. However, most of the time (but not every time) I try to run the code it returns a segmentation fault: 11 error. My guess is that the problem has something to do with fgets or my array but I don't really know.
Here's my code:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define SIZE 50
#define LENGTH 50
#define TRUE 1
#define FALSE 0
void printList(char names[SIZE][LENGTH], int length);
void toUpperCase(char names[SIZE][LENGTH], int length);
void sort(char names[SIZE][LENGTH], int length);
void startSearch(char names[SIZE][LENGTH], int length);
int binSearch(char names[SIZE][LENGTH], int l, int r, char x[LENGTH]);
int main(void){
char names[SIZE][LENGTH]; //stores the list of names
printf("Enter student names (q to stop)...\n");
int i = 0;
do {
printf("Student name #%d: ", i);
fgets(names[i], LENGTH, stdin); //fill the list of names
int len = strlen(names[i])-1; //fgets includes \n character
if(names[i][len] == '\n') //if the last character is \n
names[i][len] = '\0'; //change it to \0
if(strcmp(names[i], "") == 0)
printf("Invalid input: Type a name\n");
else
i++;
}
while(strcmp(names[i-1],"q")!=0 && i<SIZE); //Stop collecting names after input "q"
//or if the names array is full
int length = i-1; //# of names in the names array
sort(names, length);
toUpperCase(names, length);
printList(names, length);
startSearch(names, length);
printf("Done!\n");
return 0;
}
//Converts all the names in the names array to upper case
void toUpperCase(char names[SIZE][LENGTH], int length){
for(int i = 0; i < length; i++){
for(int j = 0; names[i][j]!='\n'; j++){
if(islower(names[i][j]))
names[i][j] = toupper(names[i][j]);
}
}
}
//sorts the names in the names array (bubble sort)
void sort(char names[SIZE][LENGTH], int length){
int i, j;
char temp[LENGTH];
for (i = 0; i < length-1; i++)
for (j = 0; j < length-i-1; j++)
if (strcmp(names[j],names[j+1])>0){
strcpy(temp, names[j]);
strcpy(names[j], names[j+1]);
strcpy(names[j+1], temp);
}
}
//prints the names in the names array
void printList(char names[SIZE][LENGTH], int length){
printf("Student list: [\n");
for(int i = 0; i < length; i++)
if(i == length-1)
printf("\t%s\n", names[i]);
else
printf("\t%s,\n", names[i]);
printf("]\n");
}
//The first method for searching the list
void startSearch(char names[SIZE][LENGTH], int length){
char search[LENGTH];
while(strcmp(search, "q")!=0){
printf("Enter a name to search (q to exit): ");
fgets(search, LENGTH, stdin); //gets the name to search
int len = strlen(search)-1;
if(search[len] == '\n')
search[len] = '\0';
if(strcmp(search, "q") == 0) //if entered value is q
break; //break out of the loop
//Since the list is all upper case change the search value to upper case
for(int j = 0; search[j]!='\n'; j++){
if(islower(search[j]))
search[j] = toupper(search[j]);
}
printf("Searching for %s ...\n", search);
// if binSearch returns true then the item is in the list
if(binSearch(names, 0, length-1, search) == TRUE)
printf("%s is in the list!\n", search); /
else
printf("%s is NOT in the list!\n", search);
}
}
//binary search for the names array
int binSearch(char names[SIZE][LENGTH], int l, int r, char x[LENGTH]){
while (l <= r)
{
int m = l + (r-l)/2;
if(strcmp(names[m], x) == 0)
return TRUE;
if(strcmp(names[m], x) < 0)
l = m + 1;
else
r = m - 1;
}
return FALSE;
}
I assume you're using fixed arrays of SIZE and LENGTH for learning purposes. For actual string-related work, you'd do well to heed kpra's advice and using the more complex, but more powerful, pointers (allocating them and deallocating at need).
In your reading loop you kill all the "\n"'s replacing them with zeroes.
Yet in your toUppercase() code you look for a "\n" instead of a 0x0. This risks blowing the buffer:
//Converts all the names in the names array to upper case
void toUpperCase(char names[SIZE][LENGTH], int length){
for(int i = 0; i < length; i++){
for(int j = 0; names[i][j]!='\n'; j++){
// what happens here if \n is not found and j exceeds SIZE?
if(islower(names[i][j]))
names[i][j] = toupper(names[i][j]);
}
}
}
You could replace \n with 0x0, but I think a safer loop would be:
for(int j = 0; j < SIZE; j++) {
if (yourstring[j] == 0) {
break;
}
This way you're sure never to overshoot SIZE, and the cycle is ended anyway if the end of string is found. Notice that this '\n' comparison is used also in the search loop.

How can I create a dynamic array in a procedure in C?

I'm new to this fantastic site and I found it very useful in many occasions, but now I'm dealing with a problem which I can't seem to solve.
I'm a beginner C student and I'm studying dynamic memory allocation.
I want to create a dynamic array of, let's say, integers, allocating memory for it inside a procedure, not in the main function.
This works:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *numbers; // pointer to create a dynamic array
int *test; // pointer to test realloc function
int c;
size_t i = 0;
unsigned int dim; // array's length
// allocate memory for the 1st number
numbers = malloc(sizeof(*numbers));
if (numbers == NULL) {
fputs("Error while allocating memory!\n", stderr);
} else {
printf("Insert the 1 number: ");
scanf("%d", &numbers[0]);
++i;
/* allocate memory for the other numbers,
* until the user inputs EOF
*/
while (!feof(stdin)) {
test = realloc(numbers, (sizeof(*numbers) * (i + 1)));
if (test == NULL) {
fputs("Error while allocating memory!\n", stderr);
} else {
numbers = test;
printf("Insert the %u number: ", i + 1);
scanf("%d", &numbers[i]);
++i;
}
}
dim = --i;
// print the array, 5 numbers per line
for (i = 0; i < dim; ++i) {
if (i % 5 == 0) {
puts("");
}
printf("%d ", numbers[i]);
}
puts("");
}
getchar();
return 0;
}
But I want to do this (which doesn't work):
#include <stdio.h>
#include <stdlib.h>
void get_numbers(int **numbers, unsigned int *dim);
int main()
{
int *numbers; // pointer to create a dynamic array
size_t i = 0;
unsigned int dim; // array's length
get_numbers(&numbers, &dim);
// print the array, 5 numbers per line
for (i = 0; i < dim; ++i) {
if (i % 5 == 0) {
puts("");
}
printf("%d ", numbers[i]);
}
puts("");
getchar();
return 0;
}
void get_numbers(int **numbers, unsigned int *dim)
{
int *test; // pointer to test realloc function
int c;
size_t i = 0;
// allocate memory for the 1st number
*numbers = malloc(sizeof(*numbers));
if (*numbers == NULL) {
fputs("Error while allocating memory!\n", stderr);
} else {
printf("Insert the 1 number: ");
scanf("%d", &numbers[0]); // Maybe the error is here
++i;
/* allocate memory for the other numbers,
* until the user inputs EOF
*/
while (!feof(stdin)) {
test = realloc(*numbers, (sizeof(*numbers) * (i + 1)));
if (test == NULL) {
fputs("Error while allocating memory!\n", stderr);
} else {
*numbers = test;
printf("Insert the %u number: ", i + 1);
scanf("%d", &numbers[i]);
++i;
}
}
*dim = --i;
}
}
Do I need to use a pointer to a pointer to int, right?
I know I made some mistakes but I can't figure out how to fix them.
Thanks in advance for your replies!
Bye,
Fabio Nardelli
In the first block of code, numbers is of type int*.
In the second block of code, numbers is of type int**.
You have not fixed all the places that need to be fixed because of that change.
My suggestion:
Change the input argument to numbersPtr.
Create a local variable int* numbers.
Before you return from the function, set *numbersPtr to number.
void get_numbers(int **numbersPtr, unsigned int *dim)
{
int* numbers;
...
*numbersPtr = numbers;
}
It will be better to change get_numbers to return numbers.
int* get_numbers(unsigned int *dim)
{
int* numbers;
...
return numbers;
}
and change its usage as:
numbers = get_numbers(&dim);

Resources