Need to be "pointed" in the right direction beginning C programming - c

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);
}
}

Related

Adding data from file to arrays

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 .

Develop a user-defined function to sort the array in a non-decreasing order

I just learned about pointer and tried the program on the textbook,
"Declare an array of char type with size 8, ask the user to input a
string and then assign to the array. Develop a user-defined
function to sort the array in a non-decreasing order. Print the array
before and after sorting in the main function. The function
prototype is given as
void arr_sort( char * cPtr)"
I don't know very clear what mistake I have made.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void print(char *a[]);
void arr_sort( char *a[]);
int main()
{
int i;
char *array[8];
printf("Please input a string with size 7:");
for(i=0;i<7;i++)
{
scanf("%s",array);
}
printf("the array before sorting is");
print(array);
arr_sort(array);
print(array);
return 0;
}
void arr_sort( char *a[])
{
int i,j;
char *temp;
for(i=0;i<7;i++)
{
for(j=0;j<7;j++)
{
if(strcmp(a[j],a[j+1])>0)
{
temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
}
}
}
void print(char *a[])
{
int i;
for(i=0;i<7;i++)
{
printf("%s ",a[i]);
}
}
doing a quick 'google' for a bubble sort, in C, results in:
// where 'n' is the number of entries in the array
// where 'array' is declared as 'int array[n];
for ( int c = 0 ; c < ( n - 1 ); c++ )
{
for ( int d = 0 ; d < n - c - 1; d++ )
{
if ( array[d] > array[d+1] ) /* For decreasing order use < */
{
int temp = array[d];
array[d] = array[d+1];
array[d+1] = temp;
}
}
}
Notice the limits on the upper bound of the index variables.
in your program you will be using char rather than int for temp and for the declaration of array[]
notice there is no need for anything in the string.h header file.
notice the limiting of the scope of the local variables c, d, and temp
The comments on your posted question cover the problems in the posted code, so I will not repeat all of them here.
for(i=0;i<7;i++) {
scanf("%s",array);
}
If you want 8 strings of length 7, you can't scanf them into the array. Your array is an array of pointers as defined here:
char *array[8];
Which is very different from this:
char array[8];
The first is an array that stores 8 pointers to strings. The second is an array that stores 8 characters. If you wanted to store a single string, you would do this:
char array[8];
printf("Please input a string with size 7: ");
scanf("%s", array);
Which is probably what you're used to at this point.
So, an array of pointers is just like a list of little arrows that point to blocks of memory. Your array doesn't store any characters itself, which is why you can't scanf directly into it.
int main(void) {
char *arr[8];
char new_word[8];
for(int i = 0; i < 8; i++) {
printf("Enter a new word of length 7: ");
scanf("%s", new_word);
arr[i] = malloc(strlen(new_word) + 1);
strcpy(arr[i], new_word);
}
for(int i = 0; i < 8; i++) {
printf("%s\n", arr[i]);
}
return 0;
}
This program creates two arrays: a pointer array (arr) and a character array (new_word). In the loop, you ask for seven strings of length 7, which is scanf'd into the character array. New memory is set aside for that string with malloc. Then, the string is copied into the block of memory that your first array pointer points to. We increment our array index with the for loop so that now we're using the next pointer, and so on.
It's important to use strcpy and copy the string out of the character array every time, otherwise at the end, you will just have an array of pointers pointing to a single string, new_word.

Function to count the sum of an array

Right, this is (the last) assignment for my C introduction web class.
The assignment presents the main program, does not explain anything about it and tells you to write a function to print and sum the array in it.
However I don't really understand what is going on in the main program.
Translated for your convenience;
Source code:
#include <stdio.h>
#include <stlib.h>
void print_count(int *, int);
int main(int argc, char *argv[]) {
int x, sum = 0, size = 0, array[5];
if (argc == 6) {
/* Program name and parameters received from command line */
for (x = 0; x < argc - 1; x++) {
array[x] = atoi(argv[x + 1]);
}
print_count(array, size);
} else {
printf("Error\n");
}
return 0;
}
Now I am completely clueless as to how to start writing the program requested and what variables to call/how to write the function.
Edit3: completed exercise
void print_count(int *array, int size) {
int i;
int sum = 0;
printf("Elements: ");
for (i = 0; i <= size; i++) {
printf("%d ", (array[i]);
sum = sum += array[i]);
}
printf("\nSum = %d ", sum);
return 0;
}
I would like to understand what is going on in the main program and preferably come to an answer on how to actually write the function by myself.
This:
array[5] = atoi(argv[x+1]);
is clearly wrong, it always tries to assign to array[5] which is out of bounds. It should be:
array[x] = atoi(argv[x + 1]);
This converts the x + 1:th argument from string format into an integer, and stores that in array[x]. If you're not familiar with the standard function atoi(), just read the manual page.
So if you start the program like this:
./myprogram 1 2 3 4 5
That has 6 arguments (the first is the name itself), and will end up with array containing the numbers one through five.
Then in the summing function, the first line should be something like:
void print_count(int *array, int size)
so that you give names to the arguments, which makes them usable in the function. Not providing names is an error, I think.
And it doesn't need to "interact" with main() more than it already does; main() calls print_count(), passing it a pointer to the first element of array and the length of the array, that's all that's needed to compute the sum.
Your print_count function has a few issues:
The loop runs one step too far: i should vary between 0 and size-1 included. The standard idiom for this loop is:
for (i = 0; i < size; i++) {
...
Incrementing sum is simply done with:
sum += array[i];
There is an extra ( on the first printf line.
You should print a newline after the output.
Returning 0 from a void function is invalid.
Here is a corrected version:
void print_count(int *array, int size) {
int i;
int sum = 0;
printf("Elements: ");
for (i = 0; i < size; i++) {
printf("%d ", array[i]);
sum += array[i]);
}
printf("\nSum = %d\n", sum);
}
the following proposed code:
cleanly compiles.
explains what is being accomplished at each step of the 'main()' function.
properly outputs error messages to 'stderr'.
implements the typical method to announce an error in the number of command line parameters.
Now the proposed code with explanatory comments:
#include <stdio.h> // printf(), fprintf()
#include <stdlib.h> // atoi(), exit(), EXIT_FAILURE
void print_count(int *, int);
int main(int argc, char *argv[])
{
if (argc != 6)
{
fprintf( stderr, "USAGE: %s int1 int2 int3 int4 int5\n", argv[0] );
exit( EXIT_FAILURE );
}
// implied else, correct number of arguments
// only declare variables when they are needed
int array[5];
// place each command line parameter into 'array',
// except program name
// I.E. skip the program name in argv[0]
for( int i = 1; i < argc; i++ )
{
// array[] index starts at 0, but loop counter starts at 1
array[i-1] = atoi(argv[i]);
} // end for( each value pointed at by argv[], except program name )
// print sum of command line parameters to stdout
int size = argc-1; // number of command line parameters after program name
print_count(array, size);
return 0;
} // end function: main

how to make two array strings into one array string in C

How do you make 2 array strings into 1 array string, where I can print out all the 52 playing cards?
my code:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<string.h>
int main() {
char deck[52];
char suits[] = {"Hearts","Diamonds","Clubs","Spades"};
char values[]= {"Ace","Two","Three","Four","Five","Six",\
"Seven","Eight","Nine","Ten","Jack",\
"Queen","King"};
int V, S, d = 0;
char string;
for ( S= 0; S <4; S++) {
for (V =0; V< 13; V++) {
string = strcat( values[V], suits[S]);
deck[d] = string;
printf("%s\n", string);//prints out all the 52 playing cards
d++;
}
}
return 0;
}
When I executed the program, the problem comes up which asks me to debug the program or close the program, where I closed the program in the end, which returns nothing. Can you please give me the answer which works?
Check the below code which fixes the issues in your code:
The problem with your code is you try to modify the actual string before printing and because of this there is a modified string in the next iteration. So just copy the values and suits to array and print it out as shown below.
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<string.h>
int main()
{
int i=0;
char deck[30] = "";
char suits[][30] = {"Hearts","Diamonds","Clubs","Spades"};
char values[][30]= {"Ace","Two","Three","Four","Five","Six",
"Seven","Eight","Nine","Ten","Jack",
"Queen","King"};
int V, S;
for ( S= 0; S <13; S++)
{
for (V =0; V< 4; V++){
memset(deck,0,sizeof(deck));/* Clear the buffer before writing new value*/
strcpy( deck, values[S]);
strcat(deck,suits[V]);
printf("%s\n", deck);//prints out all the 52 playing cards
i++;
}
}
printf("Number of playing cards: %d\n",i);
return 0;
}
strcat() returns a char *, a pointer to a char, not a char.
You are not even required to even consider the return value of strcat() since the destination pointer (first argument) will now contain the concatenated string, assuming enough memory is already allocated.
So here in your code, you are trying to put the concatenated string to values[V] which could fail when memory already allocated to it becomes insufficient.
The best method would be to allocate some memory (as you did with deck[]) and set it all to zeroes. Then keep strcat()ing there.
strcat(deck, values[V]);
strcat(deck, suits[S]);
An alternative to using strcpy and strcat is to use sprintf.
#include<stdio.h>
#include<string.h>
#define NUM_SUITS 4
#define CARDS_PER_SUIT 13
#define TOTAL_CARDS (NUM_SUITS * CARDS_PER_SUIT)
int main()
{
char deck[TOTAL_CARDS][24];
char* suits[NUM_SUITS] = {"Hearts","Diamonds","Clubs","Spades"};
char* values[CARDS_PER_SUIT]= {"Ace","Two","Three","Four","Five","Six",
"Seven","Eight","Nine","Ten","Jack",
"Queen","King"};
int s, c, i;
for(s = 0; s < NUM_SUITS; s++)
{
for(c = 0; c < CARDS_PER_SUIT; c++)
{
sprintf(deck[(s * CARDS_PER_SUIT) + c], "%s of %s", values[c], suits[s]);
}
}
for(i = 0; i < TOTAL_CARDS; i++)
{
printf("%s\n", deck[i]);
}
return 0;
}

String pointer issue in C code

This C program reads a line of text from keyboard and then writes the longest word in the line. The issue with my code below is that it only prints the last word apart from its length, although everything seems fine. Can anyone see a problem with my code?
#include<stdio.h>
#include<string.h>
#define MAX 132
#define MAXW 30
int Len_w[MAXW];
int Max_V(int vf[], int len);
main()
{
char s[MAX+1], w[MAXW], *Ind_w[MAXW],*p,out[MAXW];
int k=0, i=0, Maximum, g=0;
printf("\nInsert the line....\n");
p=fgets(s, MAX, stdin);
while(sscanf(p, "%s%n", w, &k)==1){
Len_w[i] = strlen(w);
Ind_w[i] = w; //the issue is here!!
p+=k+1;
i++;
}
Maximum = Max_V(Len_w,i);
for(g=0;g<i;g++){
if(Len_w[g] == Maximum){
//sscanf(Ind_w[g],"%s",out);
printf("\n%s", Ind_w[g]);
}
}
return 0;
}
/*----------------------------------------------------------------------------*/
int Max_V(int vf[], int len)
{
int j; int Max;
Max=*vf;
for(j=1; j < len; j++)
{
if(*(vf+j) > Max)
{
Max=*(vf + j);
}
}
return Max;
}
/*----------------------------------------------------------------------------*/
Ind_w[i] = w;//the issue is here!!
You let all pointers in Ind_w point to the same buffer, which is overwritten for each entered word. So only the last entered word remains "visible".
If you have it,
Ind_w[i] = strdup(w);
is a simple solution. Otherwise
Ind_w[i] = malloc(strlen(w)+1);
strcpy(Ind_w[i], w);
Both ways require the pointed-to memory to be freed when it is no longer used.
Ind_w[i] = strdup(w);//the issue is here!!
You have to duplicate the w buffer each time you read the buffer and not use the same buffer for all reading. with the way you did you will have all the array elements pointing to the same buffer and this buffer is containing the same string which is the last one read with sscanf
Note: you have to free all the duplicated buffers when they come useless. You can do it by go over the array of pointers and free each element (pointer)

Resources