Difference between char array[100] and char *array when calling functions? - c

i'd like to know why this code works fine with char tab[100] but doesn't work if I use char *tab ? fgets function takes a char* array as a parameter right ?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Int Palindrome(char* str, int i, int j);
int main()
{
char tab[100];
printf("Enter your string : \n");
fgets(tab, 100, stdin);
int j = strlen(tab);
printf("%d\n", Palindrome(tab, 0, j - 2));
return 0;
}
int Palindrome(char* str, int i, int j)
{
if (i >= j)
{
printf("My word is a Palindrome !\n");
return printf("<(^w^)>\n");
}
else if (str[i] != str[j])
{
printf("My word is not a Palindrome !\n");
return printf("<(X.X)>\n");
}
else
{
return Palindrome(str, i + 1, j - 1);
}
}

With "not work" you probably mean you get some serious error reported like a segmentation fault.
The difference between char tab[100] and char *tab is that the first has storage allocated and the second hasn't. When you call a function with an array as a parameter, then the compiler passes a pointer to the first element of the array, so for the function that got called it doesn't see the difference whether it is called with an array-parameter or with a pointer-parameter.
So to let your program work with char *tab; you must first allocate storage to this pointer, such as with char *tab=malloc(100); Now that there is valid storage allocated (and the pointer now points to it), you can call your function with this tab as parameter.

Related

Debugger gives a segmentation error for strlen

In the code below the debugger shows no error but when I run this piece of code inside a function scope char *s is also in the function scope the debugger gives a segmentation error for the strlen function. Would adding char *s as a parameter solve the problem? Or is it something else?
#include <locale.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <locale.h>
#define SIZE1 100
#define SIZE2 2000
int main() {
const char *getFileExtension(const char *filename);
char tags[100][2000];
char files[100][2000];
char paths[100][2000];
char textfiles[100][2000];
char orph[100][2000];
int i, j, k = 0;
char *s;
for (i = 0; i < SIZE1; i++) {
if (strncmp(getFileExtension(files[i]), "txt", 3) == 0) {
strcpy(textfiles[k], files[i]);
k++;
}
}
k = 0;
for (i = 0; i < SIZE1; i++) {
for (j = 0; j < SIZE1; j++) {
if (strcmp(tags[i], textfiles[j]) != 0) {
snprintf(s, strlen(tags[i]), "%s", tags[i]);
s[strlen(s) - 1] = '\0';
strcpy(orph[k], s);
k++;
}
}
}
return 0;
}
const char *getFileExtension(const char *filename) {
const char *dot = strrchr(filename, '.');
if (!dot || dot == filename)
return "";
return dot + 1;
}
EDIT: after initializing char *s and the other arrays I ran my code on devc++ and www.onlinegdb.com. It kept giving me a segmentation fault on devc++ but the code worked on the website.
You declared uninitialized arrays
char tags[100][2000];
char files[100][2000];
char paths[100][2000];
char textfiles[100][2000];
char orph[100][2000];
So using them in standard C string functions like for example
if(strcmp(tags[i],textfiles[j])!=0)
{
snprintf(s,strlen(tags[i]),"%s",tags[i]);
invokes undefined behavior.
It seems the function getFileExtension also does not set elements of the array files in this call.
getFileExtension(files[i])
Also the pointer s
char *s;
used in this statement
snprintf(s,strlen(tags[i]),"%s",tags[i]);
also has an indeterminate value.
your tags array is not initialized. so strlen has undefined behavior. snprintf requires the size of available space not the length of the (uninitialized) contents. you should use sizeof instead of strlen in the snprintf call.
The 2nd argument to snprintf is the size which was allocated to the first argument. But you allocated nothing.

how can i use pointer to move inside of this array (function) instead of array subscribting

my question is at the generate acronym function, how can i make this function work in a pointer arithmetic way instead of array subscripting.
without messing up with the structures itself, the prof prhobited array subscribting so i have to do it with pointer arithmetic instead, anyone can land a hand?
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define B 2
#define N 8
typedef struct {
int course_id;
int course_quota;
char course_name[50];
char course_code[6];
char course_acronym[N];
}course_t;
void generate_course_code(char *course_code, int course_id);
void generate_course_acronym(char *, char *);
void display();
course_t courses[B];
int main() {
int i;
for(i = 0; i < B; i++) {
printf("Enter the course name: ");
fgets(courses[i].course_name, sizeof(courses[i].course_name), stdin);
generate_course_acronym(courses[i].course_name, courses[i].course_acronym);
printf("Enter the course Quota: ");
scanf("%d", &courses[i].course_quota);
while ('\n' != getchar())
{
}
courses[i].course_id = i;
generate_course_code(courses[i].course_code, courses[i].course_id);
}
display();
return 0;
}
void generate_course_code(char *course_code, int course_id) {
char str[6];
course_id++;
strcpy(course_code, "CSE");
if (course_id < 10) {
sprintf(str, "0%d", course_id);
}
else
sprintf(str, "%d", course_id);
strcat(course_code, str);
}
void generate_course_acronym(char *course_name, char *course_acronym) {
int j = 0;
char *p = course_name;
for (course_acronym[j++] = toupper(*p); *p != '\0'; p++)
if (*p == ' ') course_acronym[j++] = toupper(*(++p));
course_acronym[j] = '\0';
}
void display() {
int x;
for (x = 0; x < B; x++) {
printf("%d. %s - %s (%s) - %d \n", ++courses[x].course_id, courses[x].course_code, courses[x].course_name, courses[x].course_acronym, courses[x].course_quota);
}
}
Because the function arguments are provided as pointers, they can be used as is to achieve your goal using pointer arithmetic as shown below:
(explanations in comments).
void generate_course_acronym(char *course_name, char *course_acronym)
{
*course_acronym = (char)toupper(*course_name); //initialize acronym to capitalized form of first character
while(*course_name) //test for end of string (NULL)
{
if(*course_name == ' ') // detect spaces between strings
{
course_acronym++; // advance acronym pointer
course_name++; // advance source pointer beyond space.
*course_acronym = (char)toupper(*course_name); // assign next acronym character
}
course_name++; // advance source to next address location
}
course_acronym++; // advance pointer to one location beyond end of acronym
*course_acronym = '\0'; // NULL terminate, making acronym a new string
}
Note: The calling function must pass enough space in course_acronym to accommodate 1 byte for each word in course_name, + 1 extra byte. For example, if course_name is defined as:
char course_name[]={"This is a fine programming class"};
then course_acronym must be defined with space for at least 7 bytes. (count of words + 1 for NULL termination)

return pointer from a function in c

Write function that gets a string s and char c that checks whether the char shows in s, if yes return a pointer to the first place that c shows in s
Here is my code. I am not sure what I did about "return the pointer", is this correct?:
#include <stdio.h>
char *foo(char s[], char c)
{
int i;
char *ptr;
for(i=0;s[i];i++)
{
if(s[i]==c)
{
printf("result: %d",i);
*ptr=i;
return ptr;
}
}
}
void main()
{
char s[]="Error404";// some string
char c='r';// some char
foo(s,c);
}
First of all, your specification is unclear. Before you start coding, make sure that the specification makes sense. It doesn't say what to do if you don't find the character, so you can't write this function before you know that.
Your function must always return something, even if the character was not found. A common way to implement this would be to return a null pointer in that case.
Your pointer should point at the found character, not at i which is an integer, that doesn't make any sense.
Correct the code into something like this:
char* foo (char s[], char c)
{
char *ptr = NULL;
for(int i=0; s[i]!='\0'; i++)
{
if(s[i]==c)
{
ptr = &s[i]; // point at the address of item number i in s
break;
}
}
return ptr; // will return NULL if not found, otherwise a pointer to the found item
}
If s is a string, then s[i] represents the ith char in the string, while s + i represents a pointer to the ith char in the string. So you want to return s + i. You probably also want to return NULL if the char is not found.
#include <stdio.h>
char *foo(char s[], char c)
{
int i;
for(i = 0; s[i]; i++)
{
if(s[i] == c)
return (s + i);
}
return (NULL);
}

Segmentation fault (11) when using malloc inside a function to form a string

I'm trying to use a function to assign space and fill that space (or at least some of it) with characters to form a string. Within the function I make a call to malloc, and within the same function I assign characters to the given space. The following code gives the general gist of what I'm doing:
#define INITIAL 10
int func(char **s);
int
main(int argc, char **argv) {
char *s;
int n;
n = func(&s);
printf("Done\n");
return 0;
}
int
func(char **s) {
int i;
*s = (char*)malloc(INITIAL*sizeof(char));
assert(*s);
for (i=0; i<5; i++) {
printf("i=%d\n", i);
*s[i] = 'a'; /*'a' is an arbitrary char for this example */
}
return i;
}
The output of this code is:
i=0
i=1
i=2
Segmentation fault: 11
The reason I have my function return an int is because I ultimately want the function to return the length of the string I have formed.
I'm completely unsure why I am getting a segmentation fault; it seems I have assigned enough space to fit the next char in. It also seems weird to me that it stops at i=2.
If anyone could identify the mistakes I have made I would greatly appreciate it!
Instead of
*s[i] = 'a';
you want
(*s)[i] = 'a';
*s[i] is equivalent to *(s[i]). That is, it treats s as an array of strings and gives you the first character of the string at index i.
*s[i] first calculate s[i], which won't be valid place for i!=0, then dereference it and try to put 'a' there. It may cause Segmentation Fault.
Try changing *s[i] to (*s)[i].
Postfix [] has higher precedence than unary *, so *s[i] is being parsed as *(s[i]), which isn't what you want; you want to dereference s and index into the result, so you need to explicitly group the * operator with s: (*s)[i].
You may want to use size_t instead of an int. Or ssize_t if you need the function to return a negative value:
#include <stdio.h>
#include <stdlib.h>
#define INITIAL 10
ssize_t func(char **);
int main(void)
{
char *s;
if((func(&s)) == -1)
{
printf("An error occurred\n");
return 1;
}
printf("Done\n");
free(s);
return 0;
}
ssize_t func(char **s)
{
size_t i = 0;
if ( INITIAL < 1 )
return -1;
if (!(*s = malloc(INITIAL*sizeof(char))))
return -1;
for (i=0; i< 5; i++) {
printf("i=%zu\n", i);
(*s)[i] = 'a';; /*'a' is an arbitrary char for this example */
}
return i;
}

Function makes an array empty

I have the following code:
#include <stdio.h>
void insertion_sort(char[], int);
void swap(char*, char*);
int main() {
char s[] = "hello world";
puts(s);
insertion_sort(s, sizeof(s)/sizeof(char));
puts("done\n");
puts(s);
return 0;
}
void swap(char* a, char* b) {
char tmp = *a;
*a = *b;
*b = tmp;
}
void insertion_sort(char s[], int n)
{
int i,j;
/* counters */
for (i=1; i<n; i++) {
j=i;
while ((j>0) && (s[j] < s[j-1])) {
swap(&s[j],&s[j-1]);
j = j-1;
}
printf("%s\n", s);
}
}
The problem is, after the insertion_sort() function call, s becomes empty - puts(s) prints nothing.
Please advise.
Change:
insertion_sort(s, sizeof(s)/sizeof(char));
to:
insertion_sort(s, strlen(s));
otherwise you will be including the '\0' terminator of s[] in your sort.
Note that you will need an additional header for strlen so change:
#include <stdio.h>
to:
#include <stdio.h> // printf etc
#include <string.h> // strlen etc
The problem is that the length that you pass to insertion_sort includes terminating \0 character, which happens to have value 0, so in sort it is placed as the first element of your array. This is why your last puts() prints nothing - because the first character is now "the end of a string".
I suggest you to calculate the size of a string using strlen() which will return the length of a string excluding terminating character. Or if you want to do it your way, take terminating character into consideration and substract it from the total length.

Resources