Sorting an array by second string - c

I have a textfile with name followed by a number that is the priority of the name, now I'm trying to sort the textfile by priority and write a new file.
old
name1 1
name2 2
name3 3
name4 1
name5 1
name6 2
name7 1
name8 3
new
name 1 1
name4 1
name5 1
name2 2
name6 2
name3 3
name8 3
I have achieved to get the old textfile in an array, but I'm stuck with sorting that array by priority. I shouldn't loop through the file again, just wanna sort the array then write that new sorted array to a new text file. How should I proceed??
The code
#include <stdio.h>
#include <stdlib.h>
typedef struct{
int p;
char *name;
}names;
int main(void){
FILE *old= fopen("old.txt", "r");
FILE *new = fopen("new.txt", "w");
char n[10];
int i =0;
names *name= malloc(sizeof(names));
for(i; i<count; i++){
int p;
char *n= malloc(sizeof(char) * 4);
fscanf(old, "%s %i", n, &p);
names[i].name= n;
names[i].p= p;
}
int j=0;
for(i=0; i < count;i++){
}
return 0;
}

Assuming that you cannot use qsort() because one of your constraints is to write your own sorting algorithm, here goes.
What do you need to sort? An array ofjob.
What is the key by which you need to sort? job.prio.
So how to sort? Any common selection, insertion, or (eek) bubble sort will do. (Though if you go down the bubble sort route, at least make it sexy and do a cocktail shaker sort.) Just compare two job.prios, both are ints so that's not hard, and swap the places of their respective job structures in the array as needed.
Here is a selection sort algorithm that will work. You can find plenty of others on Google.
void selectionSort (job* jobs, int size) {
int smallest;
job temp;
for (int i = 0; i < size - 1; i++) {
smallest = i;
for (int walk = i + 1; walk <= size - 1; walk++) {
if (jobs[walk].prio < jobs[smallest].prio)
smallest = walk;
} // end inner loop
temp = jobs[i];
jobs[i] = jobs[smallest];
jobs[smallest] = temp;
} // end outer loop
return;
}
Fairly simple; it's just like any old selection sort. But selection sort is boring. Try to do an insertion sort, now that the selection sort gives you the general idea of how to swap the elements in the array.
Note that there are other problems with your code, as folks have pointed out: you are allocating space for only one job in your array, but you need eight; you have undefined variables like eerste; you have name declared twice, once as a char* and once as an array of char. So there's plenty of cleanup, but hopefully you have enough idea now to be able to finish your assignment.

You should sort using the qsort() standard library function.
It will require you to implement a function that compares two job structures, in order to provide the sorting.
Here's one attempt:
static int compare_jobs(const void *a, const void *b)
{
const job *ja = a, *jb = b;
return ja->prio < jb->prio ? -1 : ja->prio > jb->prio;
}
You will need to call this properly (read the documentation!), then loop over your array and write the contents to a new file.

Related

A string of codes connected to multiple strings.I have some doubts about the two dimensional array and the for loop. Thank you very much!

/* link many strings*/
#include<stdio.h>
char *mystrcat(char * strDest, char * strSrc);
int main(void)
{
int n;
while(scanf("%d",&n))//输入要连接的字符串个数
{
if(n==0) break;//输入0结束
else
{
char words[n][100];
int i=0;
int j;
for(i=0;i<=n;i++)
{
while(fgets(words[i],100,stdin)!=NULL)
{
j=0;
while(words[i][j]!='\n')
j++;
if(words[i][j]=='\n') words[i][j]='\0';break;
}
}//输入字符串
for(i=n;i>0;i--)
{
mystrcat(words[i-1],words[i]);
}//连接这几个字符串
fputs(words[0],stdout);//输出字符串
printf("\n");
}
}
return 0;
}
//strcat函数原型
char *mystrcat(char * strDest,char * strSrc)
{
char *res=strDest;
while(*strDest)strDest++;
while(*strDest=*strSrc)
{
strDest++;
strSrc++;
}
return res;
}
This is a string of correct code to connect multiple strings. But I think n should be n-1 in two for cycles. But if you change the n to n-1, you can only enter n-1 strings, one less than I think. Can you tell me where my idea is wrong?
for(i=0;i<=n;i++)
Accessing array index out of bound when i=n - this is undefined behavior. So of course indexing should be from n-1 to 0( at max) or 0 to n-1.
And also array indexing in C starts from 0. So there are n elements that you are accessing, not n-1.
So corrections would be
for(i=0;i<=n-1;i++)
The thing is - you are reading in the n locations having index 0 to n-1 on the array and then you concatenate them one by one and at last all concatenated strings will be in words[0]. You are printing it out.
The second loop would be like
for(i=n-1;i>0;i--)
{
mystrcat(words[i-1],words[i]);
}
The idea is no matter what while accessing array indices don't access array index out bound. Here you can simply write it like this as shown in the second case. The thing is here we have ensured that all the indices used are from {0,1,2,3...,n-1}.
First determine what you want to do, if you want to take n string and then try to concatenate them then yes you can. That's what is being done here. but a much cleaner way to do it would be that keep a different result string on which you will concatenate n strings. That will not overwrite or change the already inputted strings.

iterating multi-dimensional arrays in C without knowing index

I'm having a problem processing a multidimensional array. I'm trying to get "123" "456" "x123" and "x456" to appear on screen inside a function using pointers:
void f(char ***array){
while (**array != '\0'){
while (*array != '\0'){
printf("%s\n",*array);array++;
}
}
}
int main(){
char* arr[50][50]={{"123","456"},{"X123","X456"}};
f(arr);
return 0;
}
When compiling, I receive the warning passing argument 1 of 'f' from incompatible pointer type at the line f(arr);. and when running the code, I see:
123
456
Segmentation fault
and the program exits.
When I change my code to this:
void f(char **array){
while (*array != '\0'){
printf("%s\n",*array);array++;
}
}
int main(){
char* arr[50]={"123","456"};
f(arr);
return 0;
}
The numbers iterate fine, but I'd rather group my data into sets at some point for better organization. Why does the first set of code with multidimensional array not execute properly?
First, why three stars? What is it that you are trying to accomplish?
The obvious solution is to create a two-dimensional array of characters, then store the string in the array, one per row. Consider the following example:
char arr[][ 6 ] = { "123", "456", "X123", "X456" };
Note that we are allowed to omit the number of rows in the arr array, but C requires that we specify the number of columns. Unfortunately, not all the strings are long enough to fill an entire row of the array, so C padded them with null characters. ( Note that there is a bit of wasted space in the array )
0 1 2 3 4 5
+-----+-----+-----+-----+-----+-----+
0 | 1 | 2 | 3 | '\0'| '\0'| '\0'|
+-----+-----+-----+-----+-----+-----+
1 | 4 | 5 | 6 | '\0'| '\0'| '\0'|
+-----+-----+-----+-----+-----+-----+
2 | X | 1 | 2 | 3 | '\0'| '\0'|
+-----+-----+-----+-----+-----+-----+
3 | X | 4 | 5 | 6 | '\0'| '\0'|
+-----+-----+-----+-----+-----+-----+
If having three stars in your code is what you want, then you will have to add one additional element which is always NULL. ( By the way, why don't you want to use the length of the array? )
Another way is to use a ragged array. C doesn't provide a "ragged array type", but it does give us the tools to simulate one. ( just create an array whose elements are pointers to strings ) Consider the following example:
#define N 4
int main( int argc, const char * argv[] ) {
char *str[] = { "123", "456", "X123", "X456" };
for ( char **p = &str[ 0 ]; p < str + N; ++p ) {
puts( *p );
}
return EXIT_SUCCESS;
}
To access one of the strings, all we need is subscript the arr array.
Hope this helps..
It is hard to tell what you are attempting to do, but if I understand correctly, you appear to have an additional array dimension that isn't required. You are testing an uninitialized value as soon as you reach the 5th string (leading to your segfault). To correct it, you could do something like:
#include <stdio.h>
void f(char **array){
while (*array != '\0'){
// while (*array != '\0'){
printf("%s\n",*array);array++;
//}
}
}
int main(){
char *arr[50]={"123","456","X123","X456",NULL};
f(arr);
return 0;
}
Output
$ ./bin/func_f
123
456
X123
X456
Note: an explicit NULL is used as a sentinel to stop iterating when the data is exhausted. There are a number of ways to handle this, this being only one.
You generally shouldn't use pointers and arrays interchangeably. The common knowledge is that they're the same, but they aren't. This is particularly true for multi-dimensional arrays.
Multidimensional arrays have to be laid out linearly in memory, since addresses are linear. There are a couple ways to do this, but C uses row-major ordering. What this means is that the last index increases fastest as addresses increase.
For example, a two dimensional array
int x[rows][cols];
the two statements would be equivalent
x[row][col] = y;
*(x + (row * cols) + col) = y;
What this means is that in order to access the elements of your multi-dimensional array in a function, the function needs to know at least the sizes of the higher dimensions to validly access.
void f(int rows, int cols, char* array[rows][cols]){
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
printf("%s\n", array[i][j]);
}
}
}
int main(){
char* arr[50][50]={{"123","456"},{"X123","X456"}};
f(50, 50, arr);
return 0;
}
However, if it is necessary to iterate without knowing the dimensions, you can take advantage of the memory layout to effectively iterate over rows and columns (and higher dimensions). Although, this adds the necessity for an entry in the array that signals an end (e.g. NULL). Aside from making the code more complex, it adds memory overhead since the last row containing the NULL generally must be allocated.
#include <stdio.h>
void f(char** array){
while (*array)
printf("%s\n", *(array++));
}
int main(){
char* arr[][2] = { {"123","456"}, {"X123","X456"}, {NULL, NULL} };
f((char**) arr);
return 0;
}

Using 2d arrays to store strings in C

I want to make a program that handles strings in 2d arrays in the following manner:
Each row represents one name only, while columns holds separate characters of each name.
Like so:
0 1 2 3 4 5
0 K e v i n \0
1 J o h n \0
2 L u c y \0
Now, the way I understand arrays is that they work as pointers for the first element. So when I read the string using the readstring(name) function even though I used a 1D array, it should work as a pointer to the 2D array and store each string as I showed above, right?
The following code is supposed to ask for three names then print them all, but it only prints the last name and some gibberish, what did I do wrong?
#include <stdio.h>
#include <stdlib.h>
void readstring(char name[]);
void get_data(char name[][15]);
void show_data(char name[][15]);
int main()
{
char name[3][15];
get_data(name);
show_data(name);
return 0;
}
void get_data(char name[][15]){
int i=0;
for(i=0;i<3;i++){
printf("\nEnter name: ");
readstring(name);
}
}
void show_data(char name[][15]){
int i;
for(i=0;i<3;i++){
printf("%s",name[i]);
}
}
void readstring(char str[]){
int i=0;
while((str[i++]=getchar())!='\n' && i<15);
str[i]='\0';
}
The output shows like this:
http://i58.tinypic.com/e7i048.jpg
The problem is here:
readstring(name);
Change it to:
readstring(name[i]);
The problem is that name is a 2 - d array, or , an array of strings. Therefore, to access one string in the array of strings, you need to use an index for that particular string.
In fact, the calling function readstring() expects a string as an argument.

C- sort array alphabetically from stdin [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I have to make a program in C which reads input from standard input and writes on the screen, strings order alphabetically. Can you please help me?
Here is the program:
#include <stdio.h>
#include <string.h>
int main (int argc, char *argv[])
{
char tabela[100][50];
int i=0;
int j,k;
char string[50];
char temp[50];
while(fgets(string,sizeof(string), stdin) != NULL)
{j=0;
while(j<strlen(string)){
tabela[i][j]=string[j++];
}
i++;
}
for(j=0; j < i ; j++){
for(k=j+1; k< i; k++)
{
if(strcmp(tabela[j],tabela[k]) > 0)
{
strcpy(temp,tabela[j]);
strcpy(tabela[j],tabela[j]);
strcpy(tabela[k],temp);
}
}
}
for (j = 0; j <i; j++){
printf("%s\n", tabela[j]);
}
// sort(tabela,i);
/* for(k = 0; k <=i;k++){
printf("\n");
for(j = 0; j <=i;j++) {
printf("%c", tabela[j][k]);
} //for */
/*
}//for */
return 0;
}//main
Thanks
One opportunity is, to run through a selection sort:
/* selection sort */
void sort(char **a, int n) {
int min, i, j;
char t[50];
for (i = 0; i < n; i++)
{
min = i;
for (j = i+1; j < n; j++)
{
if (strcmp(a[j],a[min]) < 0) min = j;
}
strcpy(t,a[min]);
strcpy(a[min],a[i]);
strcpy(a[i],t);
}
}
C/C++ provides a library for sorting in stdlib.h called "qsort" (quicksort) here
If you need an example:
Basically, you will need to include the required library "stdlib.h" and "string.h" first, then you will need to define a comparison function.
int cmp(const void* a, const void* b)
{
int arg0 = *(char*) a, arg1 = *(char*)b;
return arg0-arg1;
}
Supposed that you have a char array of length 100.
char example[100] = "adfasdfasdfsdasdfasdfafhtyjytjukvr";
Then you call the function qsort like this:
qsort(example,strlen(example),sizeof(char),cmp);
There you go :)
Alternatively, in C++, there are another built-in sorting functions std::sort() and std::stable_sort() available in the header <algorithm> which can not only work with your char array, but also other C++ containers. You may call it like this:
std::sort(example,example+strlen(example));
Further reading:
C++ containers
C++ sort
C++ stable sort
I presume this is an exercise in writing sorting code, so (to avoid doing your homework for you) I'll stick with general suggestions, based on sorting exercises and real-world sorts I've written.
Sorting a list during input from console begs for an insertion sort -- that is, sorting is done as the list is input, so that a "very short time" after pressing ENTER for each entry, the list is fully sorted (ideally, short enough the user can't tell anything was done before the next entry prompt is presented). Sorting with large list elements can be very time consuming, hence the common use of tag sorts (where you sort tags instead of the actual list elements), but it's unlikely you'll have that level of element size from manual entry. A very long list can give similar problems (depending on the efficiency of the search algorithm), but again, that's a problem limited by the entry method.
With your list limited (by array declaration) to 100 elements no more than 50 characters long, the user would never notice the delay if you used a simple step-through test and wholesale move-down for elements that need to be after the new element (on a modern computer, the sort steps after insertion wouldn't exceed a few milliseconds execution time even in an interpreting language), but (on the assumption you're learning something that will be of use later for larger programs and data sets) it's far more efficient to use a binary tree search and linked list; you could get that kind of insertion time for a list of thousands of elements each thousands of bytes long if you only have to look at a tiny fraction of them and never have to move any of them, but only shuffle integers in a tag array.

qsort not sorting and strange output

so I'm using C, I cant seem to get this to work right. It's an array of pointers to structs which contain some contact info. I can't seem to get the qsort to sort correctly.
Here is my code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 20
#define ELEMENTS 50
int sortZips(const void *a, const void *b);
typedef struct contactInfo {
char name[MAX];
char street[MAX];
char cityState[MAX];
char zipCode[MAX];
} contacts;
int main() {
int i = 0;
contacts **contactArray = malloc(ELEMENTS * sizeof(contacts *));
/* allocate array */
for (i = 0; i < ELEMENTS; i++) {
contactArray[i] = malloc(sizeof(contacts));
}
/* populate array */
for (i = 0; i < ELEMENTS; i++) {
fgets(contactArray[i]->name,MAX,stdin);
fgets(contactArray[i]->street,MAX,stdin);
fgets(contactArray[i]->cityState,MAX,stdin);
fgets(contactArray[i]->zipCode,MAX,stdin);
printf("%s", contactArray[i]->name);
printf("%s", contactArray[i]->street);
printf("%s", contactArray[i]->cityState);
printf("%s", contactArray[i]->zipCode);
}
printf("\n");
/* qsort((void *)contactArray, ELEMENTS, sizeof(contacts *), sortZips); */
for (i = 0; i < ELEMENTS; i++) {
fputs(contactArray[i]->name,stdout);
fputs(contactArray[i]->street,stdout);
fputs(contactArray[i]->cityState,stdout);
fputs(contactArray[i]->zipCode,stdout);
}
}
/* sortZips() sort function for qsort */
int sortZips(const void *a, const void *b) {
const contacts *ia = *(contacts **)a;
const contacts *ib = *(contacts **)b;
return strcmp(ia->zipCode, ib->zipCode);
}
The output is printing the addresses (I have 50 in an input file) and then some random characters, like a huge block of them, then the sorted list after that which is messed up and not sorted right.
Please any help would be appreciated. I need to learn what's wrong here and why.
Thanx.
First rule: always check input functions - in this case, fgets(). You don't know whether everything is working correctly or not if you do not check.
Second: use enum in preference to #define in general.
With the check for early EOF in place, your code sorted my sample data (6 rows) cleanly. It also compiled cleanly - which is very unusual (that's a compliment; I use stringent warnings and even my code seldom compiles cleanly the first time). My amended version of your code is very similar to yours:
int main(void)
{
int i = 0;
int num;
contacts **contactArray = malloc(ELEMENTS * sizeof(contacts *));
/* allocate array */
for (i = 0; i < ELEMENTS; i++)
contactArray[i] = malloc(sizeof(contacts));
/* populate array */
for (i = 0; i < ELEMENTS; i++)
{
if (fgets(contactArray[i]->name,MAX,stdin) == 0 ||
fgets(contactArray[i]->street,MAX,stdin) == 0 ||
fgets(contactArray[i]->cityState,MAX,stdin) == 0 ||
fgets(contactArray[i]->zipCode,MAX,stdin) == 0)
break;
printf("%s", contactArray[i]->name);
printf("%s", contactArray[i]->street);
printf("%s", contactArray[i]->cityState);
printf("%s", contactArray[i]->zipCode);
}
printf("\n");
num = i;
qsort(contactArray, num, sizeof(contacts *), sortZips);
for (i = 0; i < num; i++)
{
fputs(contactArray[i]->name,stdout);
fputs(contactArray[i]->street,stdout);
fputs(contactArray[i]->cityState,stdout);
fputs(contactArray[i]->zipCode,stdout);
}
return 0;
}
The data I used was trivial repetitions of sets of 4 lines like this:
First LastName7
7 Some Street
City, CA
95437
Note that the 'error checking' I do in the input is the bare minimum that 'works'. If you get an over-long line in the input, one field will not contain a newline, and the next will contain the next section of the input line (possibly all the rest, possibly not - it depends on how badly overlong the line is).
If your addresses are printing out rubbish at the end, then it's almost certainly because you haven't allocated enough space for them. Twenty characters is a little on the low side for addresses.
What's probably happening is that you have an address like:
14237 Verylongstreetname Avenue
and, when you do fgets (street,20,stdin);, only 14237 Verylongstree will be read (19 characters, leaving space for the null terminator).
And, here's the crux: the file pointer will still be pointing at the tname Avenue bit so that, when you try to read the cityState, you'll get that. And, when you try to read the zipCode, you'll get the cityState line, effectively stuffing up your sorting.
I believe that you have enough space. Because you are using fgets and your size of MAX, the strings should be cut to fit and have a terminating NUL at the end.
Two things that might be messing it up:
fgets will read from where it stopped reading if the line is too long. That will result in an address of "This is too long so", " it will be cut\n". And then the rest of the input will be all over the place.
If you do not have enough input to fill ELEMENTS items then you'll get whatever random data was in the malloc'd memory. If you were to use calloc instead, it would zero the memory for you. Although the better idea would be to use a counter of how many items were actually read, instead of assuming there will be ELEMENTS items.

Resources