I have a file where i have some records like that:
test one; test one; test one; 1
test two; test two; test two; 2
I need to sort those records according to the last number, so in my previous example the second record should be at the first place, since 2>1. For this, i'm trying to add each record to an array and then apply an insertion sort algorithm. I have some problems adding each part to an array, here is my current effort:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLEN 100
int main() {
char one[MAXLEN] = {};
char two[MAXLEN] = {};
char three[MAXLEN] = {};
int st[MAXLEN] = {};
int i, j;
FILE * fpointer = fopen("clients.txt", "r");
for (i = 0; i < MAXLEN; i++) {
fscanf(fpointer, "%s%s%s%d", &one[i], &two[i], &three[i], &st[i]);
}
for (j = 0; j < MAXLEN; j++) {
printf("%s", one[i]);
}
fclose(fpointer);
return 0;
}
In this example, i tried to add each field to an array, the second for loop is just a test to check whether or not data is being added to the array properly, but it's not.
you're currently scanning your data into 3 strings, shifting the offset by 1 each time, instead of 3 tables of strings.
You need to declare your data some other way. For example a 2D array of char
I suggest a structure instead, and an array of structures, so you have only one index (Here I'm assuming that max size for string is 100):
typedef struct Element
{
char one[100];
char two[100];
char three[100];
int st;
};
Element elements[MAXLEN];
now scan like this:
for (i = 0; i < MAXLEN; i++) {
Element *e = elements+i; // pointer on ith element
fscanf(fpointer, "%99s%99s%99s%d", e->one, e->two, e->three, &e->st);
}
Use & on the integer, not on the strings (already pointers, they are). Also maybe it's good to check that fscanf returns 4 (error checking). The 99s ensures that you're not overflowing your strings (max len: 100 with nul terminator)
Aside: if you have strings with spaces in it, scanf isn't going to work properly, you'll have to use fgets then strtok on the semicolons to get the items
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLEN 100
#define MAXWORDS 50
int main() {
char one[MAXWORDS][MAXLEN] = {};
char two[MAXWORDS][MAXLEN] = {};
char three[MAXWORDS][MAXLEN] = {};
int st[MAXWORDS][MAXLEN] = {};
int i, j;
FILE * fpointer = fopen("clients.txt", "r");
for (i = 0; i < MAXWORDS; i++) {
fscanf(fpointer, "%s%s%s%d", one[i], two[i], three[i], st[i]);
}
for (j = 0; j < MAXWORDS; j++) {
printf("%s", one[j]);
}
fclose(fpointer);
return 0;
}
check this program its working...!
In this program you used the fscanf() function which can fetch data from file word by word . Here you need to take care that fscanf() wont give you the spaces as well as '\n'- line termination character .
Related
Write a function common_char that takes two strings as arguments and returns a new string that contains a single copy of all characters that appear in either of the two strings.
For example, string1: hello; string2: world; the new string is : hellowrd (o and l were already in array from hello).
May use string function here.In other words, all characters in string1 are copied into the new string, but characters in string 2 are copied only characters that are not in string1. That is past exam question and the university did not provide answer. Here is my code.
#include <stdio.h>
#include <string.h>
char *common_char(char *string1, char *string2) {
int str_length1 = strlen(string1);
int str_length2 = strlen(string2);
char *new_string = malloc(str_length1+str_length2+1);
for (int index_1 = 0; index_1 < str_length1; index_1++) {
for (int index_2 = 0; index_2 < str_length2; index_2++) {
if (string1[index_1] == string2[index_2]) {
}
}
}
}
int main(void) {
return 0;
}
My idea is to find duplicate characters in string 2 and string 1 according to the nested loop, but there is a problem with the conditional statement, there is red line, also how to copy the character of the non-duplicate string? I know strcopy(), but how to remove the repeated characters?
I've come up with a solution that uses dynamic memory and resizes the result char* each time a new char must be added. There are two loops, the first iterates the b string and the second loop checks that non of char of the b string is repeated in the a string, if it is not repeated, then adds it. Hope you understand the realloc to resize dynamically the char* each time it must be added an element.
Firstly I initialize the result string to the size of string a so it can be all copied inside. The ordering method I think it is called bubble method.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char* common_char(char* a, char* b) {
char* result = (char*)malloc(sizeof(char)*strlen(a)+1);
int i = 0;
int j = 0;
int repeated = 0;
strcpy(result,a);
for(i=0; i<strlen(b); i++) {
for(j=0; j<strlen(result); j++) {
if(b[i] == a[j]) {
repeated = 1;
}
}
if(!repeated) {
result = (char*)realloc(result,strlen(result)+sizeof(char));
result[strlen(result)] = b[i];
result[strlen(result)+1] = '\0';
}
repeated = 0;
}
return result;
}
int main()
{
char a[] = "hello";
char b[] = "world";
char* result = common_char(a,b);
printf("%s", result);
return 0;
}
EDIT: I've modified the code to make it function. About the comment of memory allocation, I've modified the declaration of result to give it space for the '\0'. When doing the realloc, I've already considered that the realloc does not increment the strlen() because strlen() is a counter till the '\0' not of the size of the variable.
I need to create an array of strings, each representing a card of the Spanish deck:
#define __USE_MINGW_ANSI_STDIO 1
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
char *type[4]= {"copas", "basto", "espada", "oro"};
char *number[10]= {"Uno", "Dos", "Tres", "Cuatro", "Cinco", "Seis", "Siete", "Diez", "Once", "Doce"};
char *deck[40];
int deckIndex= 0;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 10; j++) {
char card[100] = "";
strcat(card, number[j]);
strcat(card, " de ");
strcat(card, type[i]);
strcat(card, "\n");
deck[deckIndex]= card;
deckIndex++;
}
}
for (int i = 0; i < 40; i++)
{
printf("%s\n", deck[i]);
}
return 0;
}
However, all entries of deck[] point to the same string. As a result, "Doce de oro" is printed 40 times. I don't understand why this happens, but I've theorized it's because card[] is being reinitialized in the same memory direction, and overrides what was already written there in the previous iteration. If I'm right, I would have to declare every array separately, but I have no idea how to do that without writing 40 different arrays.
Tldr:
¿Why do all entries of deck[] point to the same location?
¿How do I fix it?
(Btw suggestions for a better title are appreciated)
In C, memory on the stack is allocated in terms of Scopes. So yes, your theory is right. You are rewriting on the same location.
To fix your program, there are two possible solutions I can think of.
You can use Multidimensional Arrays.
Or you can allocate memory in heap using malloc (but make sure to free it once you are done with it)
As pointed out in the comments, in the deck[deckIndex]= card; line, you are assigning the same pointer1 to each of your deck elements – and, worse, a pointer to a variable (the card array) that is no longer valid when the initial nested for loop goes out of scope.
To fix this, you can make copies of the card string, using the strdup function, and assign the addresses of those copies to the deck elements. Further, as also mentioned in the comments, you can simplify the construction of the card string using a single call to sprintf, rather than using multiple strcat calls.
Here's how you might do that:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
char* type[4] = { "copas", "basto", "espada", "oro" };
char* number[10] = { "Uno", "Dos", "Tres", "Cuatro", "Cinco", "Seis", "Siete", "Diez", "Once", "Doce" };
char* deck[40];
int deckIndex = 0;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 10; j++) {
char card[100] = "";
sprintf(card, "%s de %s", number[j], type[i]);
deck[deckIndex] = strdup(card);
deckIndex++;
}
}
for (int i = 0; i < 40; i++) {
printf("%s\n", deck[i]);
}
// When you're done, be sure to free the allocated memory:
for (int i = 0; i < 40; i++) {
free(deck[i]);
}
return 0;
}
If your compiler does not support the strdup function (most do, and it is part of the ISO C Standard from C23), writing your own is very simple:
char* strdup(const char *src)
{
char* result = malloc(strlen(src) + 1); // Add one to make room for the nul terminator
if (result) strcpy(result, src);
return result;
}
1 Well, formally, a new card array is born on each iteration of the inner for loop, but it would be a very inefficient compiler that chose to do that, rather than simply re-using the same memory – which is clearly what is happening in your case.
I am trying to convert a string into its equivalent matrix form in C. The matrix would have 3 rows and as many columns as required. The following code doesn't compile, and I haven't figured out what's going wrong.
The error that GCC throws is:
app.c:10:25: error: subscripted value is not an array, pointer, or vector
printf("%d\n", arr[i][k]);
~~~^~
1 error generated.
Main file (app.c):
#include <stdio.h>
#include "converter.h"
int main() {
char source[] = "This is the source. "; // placeholder text
int arr = convert(source);
for (int i = 0; i < 21; i++) {
for (int k = 0; k < 3; k++) {
printf("%d\n", arr[i][k]); // error occurs at this line.
}
}
return 0;
}
converter.c file:
// Converts an input string to its respective ASCII matrix.
#include <string.h>
#include <stdio.h>
#include "converter.h"
// Converts the entire string into an multi-dimensional array.
int convert(char text[]){
// copy the input text into a local store.
char store[strlen(text)];
strcpy(store, text);
// make sure the length of the input string is a multiple of 3 or make it so.
int excess = strlen(store)%3;
char excess_spaces[3] = " ";
if (excess != 0) {
strncat(store, excess_spaces, 3-excess);
}
// covert the source into an array
int arr[3][strlen(store)/3];
int steps = strlen(store)/3;
for (int i = 0; i < steps; i++) {
int t[3];
for (int k = 0; k < 3; k++) {
t[k] = (int) store[3*i+k];
arr[k][i] = t[k];
}
}
return arr;
}
converter.h file:
int convert(char text[]);
There are multiple issues in this code.
The allocating storage for string, one must include one byte for a null terminator. Replace:
char store[strlen(text)];
with:
char store[strlen(text) + 1];
Additionally store must be big enough to contain the excess which is up to 3 spaces.
char store[strlen(text) + 3 + 1];
In C you cannot use an array as a value. It is converted to a pointer to it's first element in pretty must every context. Therefore it is not possible to return an array directly. It could be workaround by wrapping an array with a struct but it a topic for another day.
As result return arr will be equivalent to return &arr[0] which is int (*)[XXX] a pointer to int array of size XXX.
Never ever return a pointer to an object with automatic storage. It's Undefined Behaviour. I know that the intention was returning an array not a pointer to it. Create an object with dynamic storage with malloc-like function to safely return a pointer.
Returning Variable Length Array (VLA) by value is not possible because Variably Modified (VM) types cannot be defined at file scope.
It looks that indices are swapped in:
printf("%d\n", arr[i][k]);
I guess it should be arr[k][i].
Now... let's solve it.
Returning VLA is tricky. One solution is to pass a pointer to VLA as an argument. See https://stackoverflow.com/a/14088851/4989451.
The issue with this solution is that the caller must be able to compute the dimensions.
The other way it to wrap the result of the convert() to a struct. Note that the function and the struct can share the name. The result with have the sizes of VLA as n and m members and the pointer to the data as arr. The caller need to cast it to proper VM type.
To cumbersome casts between the non-trivial pointer types, one can cast via void*.
When all work with the array is done, release it memory with free().
// Converts an input string to its respective ASCII matrix.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
// Converts the entire string into an multi-dimensional array.
struct convert {
int n, m;
int *arr;
} convert(char text[]){
// copy the input text into a local store.
size_t textlen = strlen(text);
char store[textlen + 3 + 1];
strcpy(store, text);
// make sure the length of the input string is a multiple of 3 or make it so.
int excess = textlen % 3;
char excess_spaces[3] = " ";
if (excess != 0) {
strncat(store, excess_spaces, 3-excess);
}
size_t storelen = strlen(store);
// allocate VLA with dynamic storage
int (*arr)[storelen / 3] = malloc(3 * sizeof *arr);
// covert the source into an array
int steps = storelen / 3;
for (int i = 0; i < steps; i++) {
int t[3];
for (int k = 0; k < 3; k++) {
t[k] = (int) store[3*i+k];
arr[k][i] = t[k];
}
}
return (struct convert){ .n = 3, .m = steps, .arr = (int*)arr };
}
int main() {
char source[] = "This is the source. "; // placeholder text
struct convert res = convert(source);
int n = res.n, m = res.m;
int (*arr)[m] = (void*)res.arr;
for (int i = 0; i < n; i++, puts("")) {
for (int k = 0; k < m; k++) {
printf("%d ", arr[i][k]); // error occurs at this line.
}
}
free(arr);
return 0;
}
I want to make a 2D array in which the users will be able to input both strings and intergers as data. I want the first column to contain the name of each user and each row to contain their info, something like this;
name1(char) surname1(char) height1(int) weight1(int)
name2(char) surname2(char) height2(int) weight2(int)
name3(char) surname3(char) height3(int) weight3(int)
I can't figure out how to input both types of data into one array.
Edit; This is for a homework exercise which asks for a multidimensional array.
A quick solution could be storing that info in a struct better than managing multidimensional arrays.
Like
struct User {
char name[NAME_SIZE];
char surname[MAX_SURNAME];
int height;
int weight;
};
And then just having an array of User as follows:
struct User users[DESIRED_SIZE];
The proper way would be using structures but you can't. So using only arrays you can do this
char users[N][4][L];
Where N is the maximum number of users that you can store and L is the maximum number of characters for each field (name, surname, height and weight).
The problem with this array is that you read heights and weights as characters, so you would need to make a function to check whether the inputs satisfy you.
Here's a sample program -accepting only heights between 1 and 3 meters- that was written in a bad way on purpose, rewrite it properly.
#include <stdio.h>
#define N 50
#define L 20
int alphaToInt( char *s );
int main() {
char users[N][4][L];
int height = 0;
puts("Enter height please");
while( ( scanf(" %s", users[0][2]) != 1 || (height = alphaToInt(users[0][2])) < 100 || height > 300 ) && puts("Try again please...") );
printf("Height of user #0: %s\n", users[0][2]);
return 0;
}
int alphaToInt( char *s )
{
int n = 0;
for(int i = 0; s[i] >= '0' && s[i] <= '9'; i++) n = n * 10 + (s[i] - '0');
return n;
}
Here's another way
#include <stdio.h>
#define N 50
#define L 20
int checkMyAlpha( char *s );
int main() {
char users[N][4][L];
puts("Enter height please");
while( ( scanf(" %s", users[0][2]) != 1 || !(checkMyAlpha(users[0][2])) ) && puts("Try again please...") );
printf("Height of user #0: %s\n", users[0][2]);
return 0;
}
int checkMyAlpha( char *s )
{
int n = 0;
for(int i = 0; s[i] >= '0' && s[i] <= '9'; i++) {
n = n * 10 + (s[i] - '0');
if( n > 300 && (n = 1) ) break;
}
return n > 100;
}
Find your way.
What I suggest is to just use 4 different arrays for the respective field instead of a 2d array. Or you can use pair and assign one field to indicate whether it is integer or not.
Array of structure .
If you can only use arrays, you can do this:
#include <stdio.h>
#include <stdlib.h>
int main() {
char *persons[][4] = {
{"Person", "One", "123", "456"},
{"Person", "Two", "323", "756"},
};
for(int i = 0; i < 2; i++) {
printf("%s %s %i %i\n", persons[i][0], persons[i][1], atoi(persons[i][2]), atoi(persons[i][3]));
}
return 0;
}
The integer would be stored as a string, and you can use strlol to convert a string to an int. In C, you can't store mixed types in an array, unless if you want to use void *, but you probably don't want to go that route.
I used the above declaration of persons above to succinctly initialize the 3D array, but it may not make practical sense for your application. char[] creates a char array. It represents the above strings. The size is going to be the size of the characters in the initialization, so won't be able to add more chars to the end of the string. It might be better to do char *persons[80][4] instead. char[][4] creates an array of 4 of char[]; this represents 1 "row" in the above initialization. *persons[][4] points allows you to create an array of char[][4].
Davide's does what you want. However, if you want to dynamically allocate the number of persons, it'll be better to do this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef char Person[4][80];
int main() {
Person *persons = malloc(2*sizeof(Person));
strcpy(persons[0][0], "Person");
strcpy(persons[0][1], "One");
strcpy(persons[0][2], "123");
strcpy(persons[0][3], "456");
strcpy(persons[1][0], "Person");
strcpy(persons[1][1], "Two");
strcpy(persons[1][2], "323");
strcpy(persons[1][3], "756");
for(int i = 0; i < 2; i++) {
printf("%s %s %i %i\n", persons[i][0], persons[i][1], atoi(persons[i][2]), atoi(persons[i][3]));
}
return 0;
}
You don't need a typedef, but I couldn't get the code to compile just by using char. This is still one contiguous chunk of memory.
A struct is recommended:
#include <stdio.h>
struct Person {
char *name;
char *sur_name;
int height;
int weight;
};
int main() {
struct Person persons[] = {
{"Person", "One", 123, 456},
{"Person", "two", 234, 567},
};
for(int i = 0; i < 2; i++) {
printf("%s %s %i %i\n", persons[i].name, persons[i].sur_name, persons[i].height, persons[i].weight);
}
return 0;
}
and thanks for your time. I apologize in advance I am new to C programming and posting on stack overflow. Any information I may have left out and questions you have please ask.
I have this lab I am working on for my class and I'm having trouble understanding how the dreaded pointers operate. First I will explain the lab instructions.
First, I am to create an array of 200 words with a max length of 30+1 for null.
Next, call functions I need to create which include:
A read function which reads words from a file into the array. I must use fopen and fscanf functions.
A function to convert a string to lowercase using the ASCII codes of each character. (Must use pointers)
A function to return the length of a string.(Can't use strlen function and must use pointers)
A function with three parameters(array of words, # of words in array, and an int length). Function returns the number words in the array that match the int length.
A print function to print all the words in the array.
The IDE I am using is Dev C++ its been wonky so I have also been using netbeans.
I have only attempted to create the read, print, and converting to lowercase functions. I first tried to read the file and print the array in main. The file I'm reading is created by me it contains a short sentence which follows exactly:
There ARE so MANY words in HERE
EDIT- Updated main code to current with working lowercase loop inside main.
#define rows 200 //How many words allowed in array.
#define cols 31 //How many characters allowed for each word.
void lowercase(char* words, int count);
int read(char (*words)[cols]);
void print(char (*words)[31], int count);
int main(int argc, char *argv[]){
char words[rows][cols];
int i, j;
int count = read(words);
print(words, count);
/*
//make words lowercase
for(i = 0;i<count;i++){
for(j = 0;j<cols;j++){
if(words[i][j]!=0){
if(words[i][j]<91 && words[i][0]>64)
words[i][j] = words[i][j]+32;
}
}
}*/
for(i = 0;i < count;i++){
lowercase(*words+i, count);
}
print(words, count);
return 0;
}
The code is poorly written and managed properly I'm just trying to get everything to work first then it will be more appropriate. The first printf output comes out how it should:
Array [0]: There
Array [1]: ARE
Array [2]: so
Array [3]: MANY
Array [4]: words
Array [5]: in
Array [6]: HERE
Then the print function I have prints out the words correctly in the array but it includes all 30 spaces for each word instead of just the word. This is how it is written I need to change it.
void print(void *array, int SIZE){
int i,
j;
char *charArray = (char *) array;
for( j = 0; j < SIZE; j++ ){
for( i = 0; i < SIZE; i ++){
printf( "%c ", charArray[j*SIZE + i] );
}
printf( "\n" );
}
}
The tolower function I created was partially working converting the first letter of each word to lowercase. Now it is broke and do not remember what I have changed.
EDIT- updated lowercase function. The lowercase in main works exactly but with this function it doesn't convert all the words to lowercase it stops at the third word the rest are the same.
void lowercase(char *words, int count){
int j;
for(j = 0;j<cols;j++){
if(words[j]!=0){
if(words[j]<91 && words[j]>64)
words[j] = words[j]+32;
}
}
}
I tried to move the read code in main to its own function also trying to mimic the print code with the pointers but when I run the program it stalls and the exe file stopped working window pops up with command prompt.
No errors or warnings in IDE.
int read(void *array){
FILE *file;
int i,
j;
char *words = (char *) array;
file = fopen("words.txt", "r");
//STORE IN ARRAY
for(i=0;i<7;i++)
fscanf(file,"%s", words[i]);
}
If you have not figured out I have no idea when or how to use pointers or addresses. I have been taught basically all of C in literally 12 hours which is in my opinion not enough time to learn the language at all especially understand it efficiently. Any help will be greatly appreciated. Thank You.
By casting a 2-dimensional array down to a char*, you have lost some information. If you read the words in correctly, then in memory, your array might look like this:
0 10 20 30
|.........|.........|.........|.
There
ARE
so
MANY
words
in
HERE
To access words[1] the compiler is automatically offsetting 31 bytes from the beginning of the array.
Your problem is that after you cast words to char*, then the compiler no longer knows about the 2D structure, and words[1] will now only offset 1 byte from the beginning of the array.
A simple solution is to redefine your read function:
int read(char words[][31])
{
FILE *file;
int i, j, count = 0;
file = fopen("words.txt", "r");
for (i=0; i<7; i++)
{
count += (1 == fscanf(file, "%s", words[i]));
}
return count;
}
Now the compiler knows that the memory stride size for words[i] is 31 char values.
Similar thing with print:
void print(char words[][31], int count)
{
int i;
for( i = 0; i < count; i ++)
{
printf( "%s\n", words[i] );
}
}
fix like this:
#include <stdio.h>
#include <stdlib.h>
//Stringification
#define S_(n) #n
#define S(n) S_(n)
//Information to be shared across the whole area
#define MAX_ROWS 200
#define MAX_WORD_LENGTH 30
#define COLS (MAX_WORD_LENGTH + 1)
#define DATA_FILE "words.txt"
int read(void *array);
void print(void *array, int rows);
int main(void){
char words[MAX_ROWS][COLS];
int rows;
rows = read(words);
print(words, rows);
return 0;
}
int read(void *array){
FILE *file = fopen(DATA_FILE, "r");
if(file == NULL){
perror("fopen:");
exit(EXIT_FAILURE);
}
char *words = array;
int rows;
for(rows = 0; rows < MAX_ROWS; ++rows, words += COLS){
if(fscanf(file, "%" S(MAX_WORD_LENGTH) "s", words) == EOF)
break;
}
fclose(file);
return rows;
}
void print(void *array, int rows){
char *words = array;
for(int r = 0; r < rows; ++r, words += COLS){
printf("Array [%d]: %s\n\n", r, words);
}
}