Related
I ran through these few lines of code in C:
int tab[]={4,6,8,9,20};
char *p;
p=(char*)tab
And the question was how to print the value of 20 using the pointer p.
So i used a for loop to see what's going on with p
for(int i=0;i<20;i++){
printf("%d ",p[i]);
}
and i got this output:
4 0 0 0 6 0 0 0 8 0 0 0 9 0 0 0 20 0 0 0
i want to understand the logic behind those zeros appearing.
You are almost certainly using an architecture where int is 4 bytes, and a little-endian architecture where the "smallest" byte is stored first.
So the int value 4 is stored as:
+----+----+----+----+
| 4 | 0 | 0 | 0 |
+----+----+----+----+
The int value 20 gets stored as:
+----+----+----+----+
| 20 | 0 | 0 | 0 |
+----+----+----+----+
Your entire array in memory looks like:
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
| 4 | 0 | 0 | 0 | 6 | 0 | 0 | 0 | 8 | 0 | 0 | 0 | 9 | 0 | 0 | 0 | 20 | 0 | 0 | 0 |
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
Now, when you iterate over those 20 bytes as characters (and thus one byte at a time) the results should no longer be surprising.
On your machine, the sizeof an int is 4 bytes, and sizeof a char is by definition 1.
So with p, you're printing an int byte by byte.
"And the question was how to print the value of 20 using the pointer p."
As for that:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int tab[] = {4, 6, 8, 9, 20};
char *p = 0;
/* The type that & returns is a
* pointer type, in this case, a
* pointer to the 4th element of
* the array.
*/
p = (char*) &tab[4];
/* As %d expects an int, we cast
* p to an int *, and then
* dereference it.
*/
printf("%d\n", *(int *)p);
return EXIT_SUCCESS;
}
Output:
20
Edit: The above code is endian-dependent.
The code ran differently than I predicted, I think *(score+i*n+j) is problematic, it could also be a problem elsewhere, I'm not quite sure, but I don't know how to modify it.
#include <stdio.h>
#define STUD 30 // Maximum number of students possible
#define COURSE 5 // The maximum number of possible exam subjects
void Total(int *score, int sum[], float aver[], int m, int n);
void Print(int *score, int sum[], float aver[], int m, int n);
int main(void)
{
int i, j, m, n, score[STUD][COURSE], sum[STUD];
float aver[STUD];
printf("Enter the total number of students and courses:\n");
scanf("%d %d",&m,&n);
printf("Enter score:\n");
for (i = 0; i < m; i++)
{
for (j = 0; j < n; j++)
{
scanf("%d", &score[i][j]);
}
}
Total(*score, sum, aver, m, n);
Print(*score, sum, aver, m, n);
return 0;
}
void Total(int *score, int sum[], float aver[], int m, int n)
{
int i, j;
for (i = 0; i < m; i++)
{
sum[i] = 0;
for (j = 0; j < n; j++)
{
sum[i] = sum[i] + *(score + i * n + j);
}
aver[i] = (float) sum[i] / n;
}
}
void Print(int *score, int sum[], float aver[], int m, int n)
{
int i, j;
printf("Result:\n");
for (i = 0; i < m; i++)
{
for (j = 0; j < n; j++)
{
printf("%4d\t", *(score + i * n + j));
}
printf("%5d\t%6.1f\n", sum[i], aver[i]);
}
}
Example of a program running:
Enter the total number of students and courses:
2 3↙
Enter score:
90↙
95↙
97↙
82↙
73↙
69↙
Result:
90 95 97 282 94.0
82 73 69 224 74.7
Compiling your program yields no warnings or errors. Running it with the sample input you've provided yields:
Enter the total number of students and courses:
2 3
Enter score:
90
95
97
82
73
69
Result:
90 95 97 282 94.0
404780 0 82 404862 134954.0
This is correct for the first set of scores, but not the second. As you intuited, this means your math for accessing the array via pointer math is probably wrong.
Consider what your array actually looks like in memory. You've allocated on the stack an array that looks like:
+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+
Your example input has filled it like this:
+---+---+---+---+---+
| 90| 95| 97| | |
+---+---+---+---+---+
| 82| 73| 69| | |
+---+---+---+---+---+
...
If you want to access the first element of the second row, you need your offset to be i * 5 rather than i * 3 which is what happens when you use i * n. This 5 we can get from your constant COURSE.
*(score + i * COURSE + j)
When you use a different offset you get data which has not been initialized, which is why you see garbage values. If you initialize all of the values in your array to 0, but leave your code otherwise unchanged, you can see this in action.
int i, j, m, n, score[STUD][COURSE] = {0}, sum[STUD];
Enter the total number of students and courses:
2 3
Enter score:
90
95
97
82
73
69
Result:
90 95 97 282 94.0
0 0 82 82 27.3
As you note, the problem is your array accesses -- you use score[i][j] in main to fill the array and then *(score + i * n + j) in your Total and Print functions to try to access it, and these are different and incompatible. The easiest fix is probably just to fix the declarations of Total and Print to match the score you are using:
void Total(int score[][COURSE], int sum[], float aver[], int m, int n);
void Print(int score[][COURSE], int sum[], float aver[], int m, int n);
Then you can just use score[i][j] in them and everything should work. You would also pass score as just score instead of *score.
Alternately, change the declaration of score to score[STUD*COURSE] and use *(score + i * n + j) (or score[i*n + j]) in main to access it like you do in Total and Print.
OP is unclear why the code uses #defines to define values for rows and columns of the array score, then goes on to use scanf() to enter new values that may or may not conflict with the #defines, or even overflow the array memory. Either method works, but using both together confuse things. Pick one or the other.
Aside: If a dynamic sized array is necessary, then it can be created as a pointer, or pointers to allocated memory, or by use of a VLA
eg: A short example of using user input with dynamic memory allocation to create the array sized to the need of the moment:
Note: following method allows you to use plain array notation to assign values:
score[i][j] = someValue://easy to use and readable
//as opposed to
*(score + i*n + j) = someValue;// cumbersome to use and read
Example:
int student, course;//using descriptive variables
printf("Enter the total number of students and courses:\n");
scanf("%d %d",&student,&course);
int (*score)[course] = create_arr_2d (student, course);
if(score)
{ //use score
...
free(score);
}
Where create_arr_2d(...) is defined:
void * create_arr_2d (size_t x, size_t y)
{
int (*ptr_2)[x] = malloc( sizeof (int *[y]) ); //allocate a true 2D array
if(ptr_2)
{
memset(ptr_2, 0, sizeof **ptr_2);
}
return ptr_2;
}
(credit for method)
Addressing your code as is. First, the following creates variables, but does not initialize any of them:
int i, j, m, n, score[STUD][COURSE], sum[STUD];
float aver[STUD];
To eliminate some of the issues you may be seeing, initialize:
int i=0, j=0, m=0, n=0, score[STUD][COURSE]={{0}}, sum[STUD]={0};
float aver[STUD]={0};
In the function prototype in your given code:
Total(int *score, int sum[], float aver[], int m, int n)
int *score
suggests a pointer to a single dimensional array is being passed, but if it is being used to represent score[STUD][COURSE], then it should be passed as `score[m][n], with the prototype changed as:
Total(int m, int n, int score[m][n], int sum[m], float aver[m]);
Then called as:
Total(STUD, COURSE, score[STUD][COURSE], sum[STUD], aver[STUD]){...}
Note, this arrangement makes use of VLA type function arguemnts
Note also, an array such as: (shortened from your values for easier viewing)
int m = 5;
int n = 4
int array[m][n] = {{0}}
creates a single contiguous block of memory, conceivably looking like this in memory:
`|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|...`
0 5 10 15 20
Where all of the elements can be accessed in a for loop like this:
for(int i=0; i<m; i++
for(int j=0;j<n;j++)
*(array + i*n + j);
...
...
While executing the below code:
int main()
{
int abc[3][3]={0};
for(int *ip=&abc[0][0];ip<=&abc[3][3];ip++)
{
printf("%d \n",*ip);
}
}
Expected result is 9 zeros but it displays 12 data. What might be reason?
If you look at the memory layout of a 3x3 array, it looks like:
[0][0] [1][0] [2][0]
+----+----+----+----+----+----+----+----+----+
| | | | | | | | | |
+----+----+----+----+----+----+----+----+----+
Where is the element [3][3]?
[0][0] [1][0] [2][0] [3][0] [3][3]
+----+----+----+----+----+----+----+----+----+----+----+----+----+
| | | | | | | | | | | | | |
+----+----+----+----+----+----+----+----+----+----+----+----+----+
That explains why you end up accessing 12 elements.
Your code is subject to undefined behavior for accessing the beyond valid indices but that's another issue.
You could use:
for (int *ip = &abc[0][0]; ip <= &abc[2][2]; ip++)
{
printf("%d \n",*ip);
}
However, it is better to access a 2D array as a 2D array.
for (size_t i = 0; i < 3; ++i )
{
for (size_t j = 0; j < 3; ++j )
{
printf("%d \n", abc[i][j]);
}
}
#include<stdio.h>
int main()
{
int arr[3] = {2, 3, 4};
char *p;
p = arr;
p = (char*)((int*)(p));
printf("%d, ", *p);
p = (int*)(p+1); //............statement 1
printf("%d", *p);
return 0;
}
In the above code, p = (int*)(p+1); means character pointer is type cast to integer pointer. So when we dereference p, It fetches the contents up to next int size (2 bytes or 4 bytes, depending on compiler). But when I am solving this question at www.indiabix.com, they have given
answer: 2, 0
How it can be 2, 0? As per my analysis,the answer should be 2, 3. Can anyone explain what should be the correct answer and why?
Let's say an int takes four bytes.
In a little endian system, the memory layout of arr looks like:
| | <--- one byte
+---+---+---+---+---+---+---+---+---+---+---+---+
| 2 | 0 | 0 | 0 | 3 | 0 | 0 | 0 | 4 | 0 | 0 | 0 |
+---+---+---+---+---+---+---+---+---+---+---+---+
In a big endian system, the memory layout of arr looks like:
| | <--- one byte
+---+---+---+---+---+---+---+---+---+---+---+---+
| 0 | 0 | 0 | 2 | 0 | 0 | 0 | 3 | 0 | 0 | 0 | 4 |
+---+---+---+---+---+---+---+---+---+---+---+---+
In a little endian system,
*p = 2;
*(p+1) = 0;
In a big endian system,
*p = 0;
*(p+1) = 0;
Depending on your platform, the output will be:
2 0
or
0 0
The code you have is perhaps meant to confuse. The line
p = (char*)((int*)(p));
doesn't do a damn thing.
The line
p = (int*)(p+1);
has the same effect as:
p = p+1;
Playing with pointers in C is fun (not really).
I have several arrays of strings I want to declare in an easy way, preferably something like:
arrayOfStrings1 = {"word1", "word2", etc. };
arrayOfStrings2 = {"anotherword1", "anotherword2", etc. };
arrayOfStrings3 = etc.
etc.
Something similar to a translation array (but not quite), so I want to be able to swap between these during runtime. For that I want a pointer pointerToArrayOfStrings that I can swap like:
pointerToArrayOfStrings = arrayOfStrings1;
doStuff();
pointerToArrayOfStrings = arrayOfStrings2;
doSomeOtherStuff();
In my naive understanding of arrays of strings and pointers to these, this is what I tried:
// Danish transforms
const unsigned char* da_DK[] = {"b","bb","c","c","cc","d","dd","e","f","ff","g","gg","h","hh","j","j","jj","k","k","kk","l","l","l","l","ll","m","mm","n","n","nn","p","pp","r","r","r","rr","s","s","s","ss","t","t","tt","v","v","vv","æ"};
// British english transforms
const unsigned char* en_GB[] = {"a","a","a","a","a","a","a","a","a","a","a","a","a","age","ai","aj","ay","b","cial","cian","cian","dj","dsj","ea","ee","ege","ei","ei","eigh","eigh","f","f","f","g","g","gs","i","i","i","j","j","k","ks","kw","l","m","n","n","o","r","s","s","sd","sdr","sion","sion","sj","sj","tial","tion","tion","tj","u","u","u","u","w","ye","ye","z"};
// More languages....
const unsigned char** laguageStrings;
// Assign language
if (streq(language, "da-DK")){
laguageStrings= da_DK;
}
else if (streq(language, "en-GB")){
laguageStrings= en_GB;
}
else
return 0;
}
Language is a char * containing the language "en-GB", "da-DK" etc., streq() is just a home brewed (somewhat faster than strcmp()) string comparison function.
Long story short, depending on compiler this approach may work, report compiler warnings or compile, but give unexpected results.
What would be the correct way to solve this problem?
There are two way of working with array of characters (strings) in C. They are as follows:
char a[ROW][COL];
char *b[ROW];
Pictorial representation is available as an inline comment in the code.
Based on how you want to represent the array of characters (strings), you can define pointer to that as follows
char (*ptr1)[COL] = a;
char **ptr2 = b;
They are fundamentally different types (in a subtle way) and so the pointers to them is also slightly different.
The following example demonstrates the different ways of working with strings in C and I hope it helps you in better understanding of array of characters (strings) in C.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define ROW 5
#define COL 10
int main(void)
{
int i, j;
char a[ROW][COL] = {"string1", "string2", "string3", "string4", "string5"};
char *b[ROW];
/*
a[][]
0 1 2 3 4 5 6 7 8 9
+---+---+---+---+---+---+---+------+---+---+
| s | t | r | i | n | g | 1 | '\0' | | |
+---+---+---+---+---+---+---+------+---+---+
| s | t | r | i | n | g | 2 | '\0' | | |
+---+---+---+---+---+---+---+------+---+---+
| s | t | r | i | n | g | 3 | '\0' | | |
+---+---+---+---+---+---+---+------+---+---+
| s | t | r | i | n | g | 4 | '\0' | | |
+---+---+---+---+---+---+---+------+---+---+
| s | t | r | i | n | g | 5 | '\0' | | |
+---+---+---+---+---+---+---+------+---+---+
*/
/* Now, lets work on b */
for (i=0 ; i<5; i++) {
if ((b[i] = malloc(sizeof(char) * COL)) == NULL) {
printf("unable to allocate memory \n");
return -1;
}
}
strcpy(b[0], "string1");
strcpy(b[1], "string2");
strcpy(b[2], "string3");
strcpy(b[3], "string4");
strcpy(b[4], "string5");
/*
b[] 0 1 2 3 4 5 6 7 8 9
+--------+ +---+---+---+---+---+---+---+------+---+---+
| --|------->| s | t | r | i | n | g | 1 | '\0' | | |
+--------+ +---+---+---+---+---+---+---+------+---+---+
| --|------->| s | t | r | i | n | g | 2 | '\0' | | |
+--------+ +---+---+---+---+---+---+---+------+---+---+
| --|------->| s | t | r | i | n | g | 3 | '\0' | | |
+--------+ +---+---+---+---+---+---+---+------+---+---+
| --|------->| s | t | r | i | n | g | 4 | '\0' | | |
+--------+ +---+---+---+---+---+---+---+------+---+---+
| --|------->| s | t | r | i | n | g | 5 | '\0' | | |
+--------+ +---+---+---+---+---+---+---+------+---+---+
*/
char (*ptr1)[COL] = a;
printf("Contents of first array \n");
for (i=0; i<ROW; i++)
printf("%s \n", *ptr1++);
char **ptr2 = b;
printf("Contents of second array \n");
for (i=0; i<ROW; i++)
printf("%s \n", ptr2[i]);
/* b should be free'd */
for (i=0 ; i<5; i++)
free(b[i]);
return 0;
}
What would be the correct way to solve this problem?
Well, the correct way would be to use a library specifically designed for dealing with multilanguage interfaces - for instance gettext.
Another way, though patchier, would be to use a hash table (also known as "dictionary" or "hash map" or "associative map" in other languages/technologies): Looking for a good hash table implementation in C
It's probably not the answer you were looking for, but you've asked the wrong question to the right problem.