How do you pass 2-dimensional array of character into a function? - c

So i'm trying to pass
char parent[n][50];
into a function initialize();
And then copy the char x, into the parent [ i ] inside the initialize(); function. Example
x = "Cityname"
and when passed into the initialize();
it would do
strcpy(parent[i], x);
to make the
parent[i] = "Cityname"
void initialize(char *parent, int *ranks, char x, int i){
strcpy(parent[i], x);
ranks[i] = '0';
}
int main(){
int n, i = 1;
char x[20];
printf("Enter how many city are there : "); scanf("%d", &n); fflush(stdin);
char parent[n][20];
int ranks[n];
while(1){
printf("enter city name: "); scanf("%[^\n]", x);
if(i <= n){
initialize(parent[][20], ranks, x, i);
i++;
} else {
printf("The city is at maximum\n");
}
}
}
It tells a warning:
passing argument 1 of 'strcpy' makes pointer from integer without a cast
note: expected 'char *' but argument is of type 'char'
and also in function main
error: expected expression before ']' token
Can anyone explain how to strcpy(parent[i], x) correctly? I can't seem to figure this problem out.

I see several problems with your code. Arrays vs pointers in C can be confusing, so there are a few rules to keep in mind:
char x[n] can be automatically converted by the C compiler to char *x.
char x[10][20] is represented under the hood as a 1D array, and the compiler computes the offsets behind the scenes. For example, if x were a 10 x 20 array, the expression x[1][2] could be compiled as *(x + 22). For this reason, it can cause surprising results to cast a 2D array to a char*, and it is invalid to cast a 2D array to a char**.
With these rules in mind, here is how I would change your code
void initialize(char (*parent)[20], int *ranks, char *x, int i){
strcpy(parent[i], x);
ranks[i] = '0'; // Did you want an automatic conversion from char to int here? Maybe you meant ranks[i] = 0?
}
int main(){
int n, i = 0; // As Craig mentions, i should start at 0.
char x[20];
printf("Enter how many city are there : "); scanf("%d", &n); fflush(stdin);
char parent[n][20];
int ranks[n];
while(1){
printf("enter city name: "); scanf("%19s", x); // scanf will automatically stop at whitespace, and you must include the max length to avoid a buffer overrun.
if(i < n){
initialize(parent, ranks, x, i);
i++;
} else {
printf("The city is at maximum\n");
// Maybe break here, unless you want an infinite loop
}
}
}

Related

Segmentation fault in C program using pointers as parameters

Im trying to understand pointers as function parameters, and in one of the programs there is a segmentation error I can't fix. Firstly, why to use pointers in function arguments? and Why is this error showing?
#include <stdio.h>
void square_it(int* a)
{
printf("The final value is: %d\n", *a * *a);
}
int main()
{
int* input;
puts("This program squares the input integer number");
puts("Please put the number:");
scanf("%d", &input);
square_it(input);
return 0;
}
int* input; does not allocate memory for an int. It mearly makes it possible to make input point at an int (allocated elsewhere). Currently, by dereferencing it (like you do with *a), you make your program have undefined behavior. If you really want an intermediate pointer variable for this, this example shows how it could be done:
#include <stdio.h>
void square_it(int *a) {
*a *= *a; // same as *a = *a * *a;
}
int main() {
int data;
int* input = &data; // now `input` points at an `int`
puts("This program squares the input integer number");
puts("Please put the number:");
// check that `scanf` succeeds:
if(scanf("%d", input) == 1) { // don't take its address, it's a pointer already
square_it(input);
// since `input` is pointing at `data`, it's actually the value of `data`
// that is affected by `scanf` and `square_it`, which makes the below work:
printf("The final value is: %d\n", data);
}
}
Without an intermediate pointer variable:
#include <stdio.h>
void square_it(int *a) {
*a *= *a;
}
int main() {
int input; // note that it's not a pointer here
puts("This program squares the input integer number");
puts("Please put the number:");
if(scanf("%d", &input) == 1) { // here, taking the address of `input` makes sense
square_it(&input); // and here too
printf("The final value is: %d\n", input);
}
}
Without any pointers at all, it could look like this:
#include <stdio.h>
int square_it(int a) {
return a * a;
}
int main() {
int input;
puts("This program squares the input integer number");
puts("Please put the number:");
if(scanf("%d", &input) == 1) { // here, taking the address of `input` makes sense
int result = square_it(input);
printf("The final value is: %d\n", result);
}
}
This is the working code:
#include <stdio.h>
void square_it(int* a)
{
printf("The final value is: %d\n", *a * *a);
}
int main()
{
int i = 0;
int* input = &i;
puts("This program squares the input integer number");
puts("Please put the number:");
scanf("%d", input);
square_it(input);
return 0;
}
There are some errors in the original code:
According to the man-pages to scanf, it takes a format string and then the address of where to store the input.
You gave it the address of a pointer (eg. an int**), which is not what scanf expects.
Also you need to provide memory to store the input in. The scanf string tells that you want an integer as input. In the above code snippet that is i.
input points to i, so i can give the int*, that is input to scanf. scanf will then write into i. We can then go ahead and put the address of i into the sqare_it function.
Since we did not use the heap, we don't need to worry about memory management.

Why do we not use an indirection operator when trying to access element of an array using a pointer?

I have a program that asks for a number of students and then for each of their first, last names and studentID. I'm attempting to print each of the values that are stored in the array of students. However, I get an error on the line printf("%d\n", *(students+i)->studentID); of Indirection requires pointer operand ('int' invalid).
I tried changing the line to printf("%d\n", (students+i)->studentID); and it seems to work. Why is this happening and why don't we need to do this for the print statements above that are printing characters? Thanks
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Students {
char firstName[20];
char lastName[20];
int studentID;
} Student;
void printRecords(Student *students, int size){
for(int i = 0; i < size; i++){
printf("%c\n", *(students+i)->firstName); // prints
printf("%c\n", *(students+i)->lastName); // prints
printf("%d\n", *(students+i)->studentID); // does not print
}
}
int main(int argc, const char * argv[]) {
int number_of_records;
printf("Please enter the number of records you would like to add:\n");
scanf("%d", &number_of_records);
Student *S;
S = (Student*)malloc(sizeof(Student) * number_of_records);
for(int i = 0; i < number_of_records; i++){
printf("First name of student %d\n", i+1);
scanf("%s/n", S[i].firstName);
printf("Last name of student %d\n", i+1);
scanf("%s/n", S[i].lastName);
printf("StudentID of student %d\n", i+1);
scanf("%d/n", &S[i].studentID);
}
printRecords(S, number_of_records);
}
*(students+i)->studentID is an equivalent of *((students+i)->studentID)
You try to dereference the integer and you get the compile error.
The first compiles ok because
*(students+i)->firstName is the same as *((students+i)->firstName) and the member firstName is an array which decays to the pointer of the char * type. You can of course dereference pointers.
-> is an (implicit) indirection operator -- a->b is the same as (*a).b. So when you write
*(students+i)->studentID
that's the same as
*(*(students+i)).studentID
with TWO indirection operations.
You can use the indirection operator here, but then you use the member operator . instead of ->:
printf("%d\n", (*(students+i)).studentID);
This is semantically the same as
printf("%d\n", (students+i)->studentID);

program returning garbage values even after declaring variables in c

how do i correct this
i didn't use structure intentionally
this is a program to input student's name, subject and marks.
in the last block, the array (subject+f) 's 1st subscript is returning garbage values while the rest subscript are returning desired result.
i have also posted the image of output as link.
#include<stdio.h>
#include<string.h>
int main()
{
int size,i,k,sub,a=0,reference;
int temp,sorted;
char temp_s[10];
char temp_sb[10];
printf("enter the size of class\n");
scanf("%d",&size);
printf("how many subjects are there?\n");
scanf("%d",&sub);
reference = sub;
char name[size][20];
char subject[size*sub][20];
int marks[sub*size];
int total,subtotal,retotal;
for(k=0;k<sub;k++)
{
printf("so what's the no. %d subject\n",k+1);
scanf(" %s",(subject[k]));
}
for(i=0;i<size;i++)
{
int j,k=0;
printf("Enter a name of student %d\n",i+1);
scanf(" %s",(name+i));
for(j=a;j<reference;j++)
{
printf("enter marks of %s\n",(subject[k]));
scanf("%d",(marks+j));
k++;
}
a=j;
reference=sub+j;
}
reference=sub;
a=0;
printf("\n list of students and marks:\n");
for(i=0;i<size;i++)
{
int j,f=0;
printf("%s\n",(name+i));
for(j=a;j<reference;j++)
{
printf("%s %d\n",(subject[f]),(marks[j]));
f++;
}
a=j;
reference=sub+j;
}
}
Besides the problem with length of names and subjects, this here is a major problem:
(subject+k)
You are probably misunderstanding the subject[k] and *(subject + k) equivalent.
The variable subject is an array of arrays. That means subject[i] is an array (of char and can be used as a zero-terminated string).
The expression (subject + k) is a pointer to the array in subject[k]. It's equal to &subject[k] which have the type char (*)[10]. It's can not be used as a zero-terminated string without dereferencing. So either use *(subject + k) or the simple, less-to-write and easier-to-read subject[k].
I think you also need to change
int marks[sub];
to
int marks[size * sub];
one mark for each subject for each student, correct?

In C arrays are not assignable so why is this program working?

In C arrays are not assignable, but in line 36 (line that I have also commented on) I assign a value to the array name without getting any errors. Why is this happening? Also, aside from this baffling thing I would really appreciate if you checked whether my freeStudents function is working properly. Thanks for your time guys!
#include <stdio.h>
#include <stdlib.h>
#define MAX_NAME 50
struct students
{
char name[MAX_NAME];
float average;
};
void storeStudents(struct students *lst, int n);
void printStudents(struct students *lst, int n);
void freeStudents(struct students *lst);
int main(void)
{
int n;
printf("How many students you wanna store? ");
scanf("%d", &n);
struct students *list;
list = (struct students *)malloc(n*sizeof(struct students));
storeStudents(list,n);
printStudents(list,n);
freeStudents(list);
return 0;
}
void storeStudents(struct students *lst, int n)
{
int i;
for(i=0;i<n;i++)
{
printf("Name of student: ");
scanf("%s", &(lst[i].name)); //In C arrays are not assignable, so why is this line working?
printf("Average of student: ");
scanf("%f", &(lst[i].average));
}
printf("\n");
}
void printStudents(struct students *lst, int n)
{
int i;
for(i=0;i<n;i++)
{
printf("Name: %s\tAverage: %.2f", lst[i].name, lst[i].average);
printf("\n");
}
}
void freeStudents(struct students *lst)
{
free(lst);
}
In C you cannot assign an array to another, basically because an array cannot be on the left side of an assignment. So the following:
char a[5] = { 1, 2, 3, 4, 5 };
char b[5];
b = a;
is not correct. But of course this is correct:
b[0] = a[0];
b[1] = a[1];
b[2] = a[2];
b[3] = a[3];
b[4] = a[4];
because b[0] (which is *(b+0)) is not an array, but a char.
Now to the point. In line 36 you do:
scanf("%s", &(lst[i].name));
A comment before dissecting: don't use scanf() for user input.
Anyway, the function is a variable argument function, meaning that it will happily accept anything you pass as the second parameter. But what you should be passing there is a char* (a pointer to char). Why? Because the guys who devised the function decided so: when the format string has a %s you need a char* parameter.
What type is &(lst[i].name)? The expression lst[i].name is of type char[50] (an array of 50 char), so &(lst[i].name) is "the address of an array of 50 char", which in C is called "a pointer to an array of 50 char" or in C syntax char(*)[50]. Which is not a char*. So this is wrong or better Undefined Behavior.
What should the correct version have been? Well, this:
scanf("%s", lst[i].name);
because when you use an array in an expression it decays to a pointer to the first element.
Ok, but why does it work anyway? It may work on some compilers, because they just pass the address of the array in both cases, so on the stack both things are the same number.
Finally, no array is "assigned" in this expression statement, thus the question in fact makes no sense in the first place. Or better, the function receives the address of the array and fills it using that pointer to the first element. Another funny thing is that you cannot have functions with array parameters. Only pointers.

Using an Array to print out a number of asterisks, dependent on number inputted from user in C

So this program should print out the number of asterisks dependending on the number you enter, so if you enter 5, the 5 asterisks will print out.
I don't know where I am going wrong? Also if anyone can recommend a good book for C, I read through my school text and C for dummies, I am just not getting it.
void barplot(int num1, char array[]);
int main()
{
int n1;
printf("Enter a number: ");
scanf("%d",&n1);
printf("You have entered: %d\n",n1);
char astrk[n1];
strcpy(astrk, "*");
barplot(n1, astrk);
return(0);
}
void barplot(int num1, char array[])
{
printf("num1=%d\n",num1);
int i=0;
for(i=0; i<num1; i++)
{
printf("%c",array[i]);
}
}
Edit: An array is needed per the assignment
Given that you're stuck using an array, you can fill the astrk array with '*' characters using memset:
char astrk[n1];
memset(astrk, '*', n1);
barplot(n1, astrk);
return 0;
memset fills the array (the first argument) with copies of the character (the second argument), up to the length in the third argument. Note that this doesn't null-terminate the array, so you can't directly printf it.
If you do want to be able to printf it, then you should allocate enough space for the null terminator, like so:
char astrk[n1+1];
memset(astrk, '*', n1);
astrk[n1] = '\0'
printf("%s", astrk);
return 0;
Then you don't need the barplot function at all.
You don't really need a whole char array just to store one character. Let's just replace the char[] with a single char:
void barplot(int num1, char array);
int main()
{
int n1;
printf("Enter a number: ");
scanf("%d", &n1);
printf("You have entered: %d\n", n1);
barplot(n1, '*');
return 0;
}
void barplot(int num1, char ch)
{
printf("num1=%d\n",num1);
int i;
for(i=0; i<num1; i++)
{
putchar(ch);
}
}
You did not filled your astrk array with asterisks. You just copied over a string literal that has only one asterisk.
If you need only to print these asterisks, why do you need an array at all?
try this:
void barplot(int num1)
{
printf("num1=%d\n",num1);
for(i=0; i<num1; i++)
{
printf("*");
}
printf("\n");
}
void barplot(int num1)
{
char s[BUFSIZ];
memset(s,'*',BUFSIZ);
printf("%.*s",num1%BUFSIZ,s);
}
I wonder why it has not been mentioned that standard c does not allow variable length arrays. You can do variable length arrays in C99 (ISO/IEC 9899:1999) but they are not part of C++ or standard C. It might be supported by some compilers but there is always a risk.
Besides i am certain that above question being an assignment, was given with the intention that size determined at run time should be handled using dynamic allocation such as malloc.
char arr[SIZE]; // size has to be a constant value or a variable with const modifier
Size cannot be determined at run time for the above syntax.
You should use malloc as a standard practice
char *arr = malloc(n1);
This needs to be freed latter too
free(arr);

Resources